Heading
Semantic heading with configurable element, size, color, and weight.
| Prop | Type | Default |
|---|---|---|
| as | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "h2" |
| size | "xl" | "lg" | "md" | "sm" | "xs" | "md" |
| color | "root" | "root-contrast" | "root-100" | "root-100-contrast" | "root-200" | "root-200-contrast" | "primary" | "primary-contrast" | "secondary" | "secondary-contrast" | "accent" | "accent-contrast" | "root-contrast" |
| weight | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | — |
Heading xl
Heading lg
Heading md
Heading sm
Heading xs
<Heading size="xl">Heading xl</Heading>
<Heading size="lg">Heading lg</Heading>
<Heading size="md">Heading md</Heading>
<Heading size="sm">Heading sm</Heading>
<Heading size="xs">Heading xs</Heading>Root Contrast
Primary
Secondary
Accent
<Heading color="root-contrast">Root Contrast</Heading>
<Heading color="primary">Primary</Heading>
<Heading color="secondary">Secondary</Heading>
<Heading color="accent">Accent</Heading>Light (300)
Normal (400)
Semibold (600)
Bold (700)
Black (900)
<Heading weight={300}>Light (300)</Heading>
<Heading weight={400}>Normal (400)</Heading>
<Heading weight={600}>Semibold (600)</Heading>
<Heading weight={700}>Bold (700)</Heading>
<Heading weight={900}>Black (900)</Heading>import { Heading } from "@/ui";
<Heading>Title</Heading>src/ui/Heading.tsx
import { cn } from "@/utils";
type HeadingColor =
| "root"
| "root-contrast"
| "root-100"
| "root-100-contrast"
| "root-200"
| "root-200-contrast"
| "primary"
| "primary-contrast"
| "secondary"
| "secondary-contrast"
| "accent"
| "accent-contrast";
type HeadingSize = "xl" | "lg" | "md" | "sm" | "xs";
type HeadingElement = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
type FontWeight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
const weightClass: Record<FontWeight, string> = {
100: "font-thin",
200: "font-extralight",
300: "font-light",
400: "font-normal",
500: "font-medium",
600: "font-semibold",
700: "font-bold",
800: "font-extrabold",
900: "font-black",
};
const sizeClass: Record<HeadingSize, string> = {
xl: "text-6xl font-bold leading-tight tracking-tight text-balance md:text-7xl lg:text-9xl",
lg: "text-5xl font-semibold leading-tight tracking-tight text-balance sm:text-6xl lg:text-7xl",
md: "text-3xl font-semibold leading-tight text-balance sm:text-4xl",
sm: "text-2xl font-semibold leading-snug text-balance",
xs: "text-base font-semibold leading-snug",
};
const colorClass: Record<HeadingColor, string> = {
root: "text-root",
"root-contrast": "text-root-contrast",
"root-100": "text-root-100",
"root-100-contrast": "text-root-100-contrast",
"root-200": "text-root-200",
"root-200-contrast": "text-root-200-contrast",
primary: "text-primary",
"primary-contrast": "text-primary-contrast",
secondary: "text-secondary",
"secondary-contrast": "text-secondary-contrast",
accent: "text-accent",
"accent-contrast": "text-accent-contrast",
};
interface HeadingProps
extends Omit<React.HTMLAttributes<HTMLHeadingElement>, "color"> {
as?: HeadingElement;
size?: HeadingSize;
color?: HeadingColor;
weight?: FontWeight;
}
export function Heading({
as: Tag = "h2",
size = "md",
color = "root-contrast",
weight,
className,
children,
...props
}: HeadingProps) {
return (
<Tag
className={cn(
sizeClass[size],
colorClass[color],
weight && weightClass[weight],
className,
)}
{...props}
>
{children}
</Tag>
);
}