Lexington has been awarded a grant from Astro, to celebrate. Get a 30% discount. Apply code LEXINGTON30 ( uppercase ) at checkout.
Hello eveyrone, today we are making a typography component for your Astro Js and Tailwind CSS project.
Consistent typography is key to keeping your website looking clean and organized. Without it, things can start to look messy fast. A typography component helps keep text styling uniform across your whole site. The idea here is to make it both flexible and well-defined, so you get a good balance between structure and creativity, since not everything is just black and white. ‘
Create your file for the component, in this we are calling it <Text />
we will be using the tag
prop to specify the HTML tag to render and the variant
prop to specify the variant of the text.
This section allows you to customize your typography component using various props. You can choose the HTML tag for semantic correctness, define style variants, indicate heading levels for accessibility, and add custom CSS classes for additional styling. Other props help link labels to form controls, assign unique IDs for targeting, and set URLs for anchor tags.
Using these props, you can create a flexible typography component that fits your project’s requirements while keeping a consistent look and feel.
NOTE: While you can define a link tag a
and add a href
attribute, I would create a separate component for links, because sometimes this ones look like buttons. Is a way to create a much cleaner component. Why did I add here? Well so you can see that it’s possible.
export interface Props {
tag?:
| "h1"
| "h2"
| "h3"
| "h4"
| "h5"
| "h6"
| "p"
| "a"
| "em"
| "div"
| "span"
| "small"
| "label"
| "strong"
| "summary"
| "blockquote";
variant?: string;
level?: number;
class?: string;
for?: string;
id?: string;
href?: string;
}
These are the styles I decided to use, but you can define your own ones, I have defined many levels, but is because I like to have it all prepared in case I need it. Do you need to create so many? Well most likely not, but it does not hurt to have them there just in case.
const textStyles: { [key: string]: string } = {
display6XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-9xl lg:text-[12rem]",
display5XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-8xl lg:text-[10rem]",
display4XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-8xl lg:text-9xl",
display3XL:
"text-4xl leading-tight tracking-tight sm:text-6xl md:text-7xl lg:text-8xl",
display2XL:
"text-4xl leading-tight tracking-tight sm:text-5xl md:text-6xl lg:text-7xl",
displayXL:
"text-3xl leading-tight tracking-tight sm:text-4xl md:text-5xl lg:text-6xl",
displayLG:
"text-2xl leading-tight tracking-tight sm:text-3xl md:text-4xl lg:text-5xl",
displayMD:
"text-xl leading-tight tracking-tight sm:text-2xl md:text-3xl lg:text-4xl",
displaySM: "text-lg leading-tight sm:text-xl md:text-2xl lg:text-3xl",
displayXS: "text-base leading-tight sm:text-lg md:text-xl lg:text-2xl",
textXL: "text-lg leading-normal sm:text-xl md:text-2xl",
textLG: "text-base leading-normal sm:text-lg md:text-xl",
textBase: "text-base leading-normal",
textMD: "text-base leading-normal ",
textSM: "text-sm leading-normal ",
textXS: "text-xs leading-normal ",
};
This code snippet is part of your Astro component and serves several important functions:
Destructuring Props: It extracts values from the Astro.props
object, assigning default values if they are not provided. This includes:
tag
: Defaults to "p"
(paragraph) if no tag is specified.variant
: Defaults to "textMD"
for styling if no variant is provided.level
: Defaults to 2
, which is used for heading levels.className
: Allows for additional CSS classes.htmlFor
: Captures the for
attribute typically used with labels.Base Class Retrieval: It retrieves the base styling classes associated with the specified variant
from the textStyles
object. If the variant isn’t found, it defaults to the "textMD"
variant.
Combining Classes: It combines the base classes with any additional classes passed in via the className
prop. The result is a single string of classes that can be used for styling the component.
Tag Resolution for Headings: If the specified tag
is one of the heading elements (h1
, h2
, h3
, h4
, h5
, h6
), it adjusts the tag
based on the level
prop. It ensures that the heading level is between 1 and 6, enforcing proper semantic HTML structure.
In summary, this code snippet allows for flexible and customizable typography in your Astro component, enabling you to specify how text should be displayed while maintaining semantic correctness and styling consistency.
const {
tag: Tag = "p", // default to paragraph
variant = "textMD", // default to textMD variant
level = 2, // default to level 2 for headings
class: className = "",
for: htmlFor, // Capture 'for' attribute
...rest
} = Astro.props;
// Get the base classes for the variant
const baseClasses = textStyles[variant] || textStyles.textMD; // Default to textMD if not found
// Combine base classes with any additional custom classes
const combinedClasses = `${baseClasses} ${className}`.trim();
// Adjust the tag based on the level for headings
let resolvedTag: string = Tag; // Ensure resolvedTag is a string
if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(Tag)) {
resolvedTag = `h${Math.min(Math.max(level, 1), 6)}`; // Enforce level to be between 1 and 6
}
This section of the code renders the typography component using the specified HTML tag (<Tag>
). It applies the combined CSS classes for styling and uses slots to allow for flexible content placement:
<Tag>
element renders based on the tag
prop.class
attribute is set to combinedClasses
, ensuring proper styling.<slot name="left-icon" />
: For optional content on the left.<slot />
: For the main text content.<slot name="right-icon" />
: For optional content on the right.This structure provides versatility in how text and icons can be displayed within the component.
<Tag class="{combinedClasses}" {...rest}>
<slot name="left-icon" />
<slot />
<slot name="right-icon" />
</Tag>
---
export interface Props {
tag?:
| "p"
| "a"
| "span"
| "small"
| "div"
| "strong"
| "em"
| "blockquote"
| "summary"
| "label"
| "h1"
| "h2"
| "h3"
| "h4"
| "h5"
| "h6";
variant?: string;
level?: number;
class?: string;
for?: string;
id?: string;
href?: string;
}
const textStyles: { [key: string]: string } = {
display6XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-9xl lg:text-[12rem]",
display5XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-8xl lg:text-[10rem]",
display4XL:
"text-4xl leading-tight tracking-tight sm:text-7xl md:text-8xl lg:text-9xl",
display3XL:
"text-4xl leading-tight tracking-tight sm:text-6xl md:text-7xl lg:text-8xl",
display2XL:
"text-4xl leading-tight tracking-tight sm:text-5xl md:text-6xl lg:text-7xl",
displayXL:
"text-3xl leading-tight tracking-tight sm:text-4xl md:text-5xl lg:text-6xl",
displayLG:
"text-2xl leading-tight tracking-tight sm:text-3xl md:text-4xl lg:text-5xl",
displayMD:
"text-xl leading-tight tracking-tight sm:text-2xl md:text-3xl lg:text-4xl",
displaySM: "text-lg leading-tight sm:text-xl md:text-2xl lg:text-3xl",
displayXS: "text-base leading-tight sm:text-lg md:text-xl lg:text-2xl",
textXL: "text-lg leading-normal sm:text-xl md:text-2xl",
textLG: "text-base leading-normal sm:text-lg md:text-xl",
textBase: "text-base leading-normal",
textMD: "text-base leading-normal ",
textSM: "text-sm leading-normal ",
textXS: "text-xs leading-normal ",
};
const {
tag: Tag = "p", // default to paragraph
variant = "textMD", // default to textMD variant
level = 2, // default to level 2 for headings
class: className = "",
for: htmlFor, // Capture 'for' attribute
...rest
} = Astro.props;
// Get the base classes for the variant
const baseClasses = textStyles[variant] || textStyles.textMD; // Default to textMD if not found
// Combine base classes with any additional custom classes
const combinedClasses = `${baseClasses} ${className}`.trim();
// Adjust the tag based on the level for headings
let resolvedTag: string = Tag; // Ensure resolvedTag is a string
if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(Tag)) {
resolvedTag = `h${Math.min(Math.max(level, 1), 6)}`; // Enforce level to be between 1 and 6
}
---
<Tag
class={combinedClasses}
{...rest}>
<slot name="left-icon" />
<slot />
<slot name="right-icon" />
</Tag>
To use the typography component in your site, you can specify the desired properties when rendering it. For example:
<Text tag="p" variant="display6XL"> Display 6XL </Text>
In this tutorial, we created a versatile typography component for your Astro and Tailwind CSS project. By using props, you can easily customize how your text looks and behaves, ensuring it fits well with your site’s design.
With the examples provided, you can now integrate this component into your website, enhancing your text’s visual appeal and accessibility. Feel free to modify it further to meet your specific needs!
/Michael Andreuzza
Get lifetime access to every theme available today for $199 and own
them forever. Plus, new themes, lifetime updates, use on unlimited
projects and enjoy lifetime support.
— No subscription required!