# Heading

A semantic heading with independent size, weight, and tone controls.

## Installation

```bash
npx shadcn@latest add https://reactdocs.canceydejean.dev/r/heading.json
```

[Registry JSON](https://reactdocs.canceydejean.dev/r/heading.json)

## Preview

```tsx
import Heading from "@/components/ui/heading/heading";
import { HEADING_SIZES } from "@/components/ui/heading/heading.variants";

export function Preview() {
  return (
    <div className="flex flex-col gap-4">
      {HEADING_SIZES.map((size) => (
        <Heading key={size} level="h2" size={size}>
          Heading
        </Heading>
      ))}
    </div>
  );
}
```


## Source

### heading.tsx

```tsx
import { cn } from "cn";

import type { HeadingProps } from "./heading.types";
import { headingVariants } from "./heading.variants";

export default function Heading({
  level = "h1",
  size,
  weight = "semibold",
  tone = "default",
  className,
  ...props
}: HeadingProps) {
  const Tag = level;

  return (
    <Tag
      data-slot="heading"
      data-size={level}
      className={cn(headingVariants({ size, weight, tone }), className)}
      {...props}
    />
  );
}
```


### heading.types.ts

```ts
import type { VariantProps } from "class-variance-authority";

import type { headingCva } from "./heading.variants";

export type HeadingVariantProps = VariantProps<typeof headingCva>;

export type HeadingProps = {
  level?: NonNullable<HeadingVariantProps["level"]>;
  size?: HeadingVariantProps["size"];
  weight?: HeadingVariantProps["weight"];
  tone?: HeadingVariantProps["tone"];
} & React.ComponentPropsWithoutRef<"h1">;
```


### heading.variants.ts

```ts
import { cva } from "class-variance-authority";

import { cn } from "cn";

const headingBase = cn("leading-none tracking-tight");

const headingConfig = {
  variants: {
    level: {
      h1: "",
      h2: "",
      h3: "",
      h4: "",
      h5: "",
      h6: "",
    },
    size: {
      xs: "[font-size:var(--text-18)] sm:[font-size:var(--text-20)]",
      sm: "[font-size:var(--text-20)] sm:[font-size:var(--text-24)]",
      md: "[font-size:var(--text-24)] sm:[font-size:var(--text-30)]",
      lg: "[font-size:var(--text-30)] sm:[font-size:var(--text-36)]",
      xl: "[font-size:var(--text-36)] sm:[font-size:var(--text-48)]",
      "2xl": "[font-size:var(--text-48)] sm:[font-size:var(--text-60)]",
      "3xl": "[font-size:var(--text-60)] sm:[font-size:var(--text-72)]",
    },
    weight: {
      regular: "font-normal",
      medium: "font-medium",
      semibold: "font-semibold",
      bold: "font-bold",
      extrabold: "font-extrabold",
    },
    tone: {
      default: "text-foreground",
      muted: "text-muted-foreground",
      danger: "text-destructive",
      success: "text-green-600",
      warning: "text-yellow-600",
    },
  },
  compoundVariants: [],

  defaultVariants: {
    level: "h1",
    size: "md",
    weight: "semibold",
    tone: "default",
  },
} as const;

export const headingCva = cva(headingBase, {
  ...headingConfig,
  compoundVariants: [...headingConfig.compoundVariants],
});

// Export the level variants
export const HEADING_LEVELS = Object.keys(
  headingConfig.variants.level,
) as unknown as (keyof typeof headingConfig.variants.level)[];

// Export the size variants
export const HEADING_SIZES = Object.keys(
  headingConfig.variants.size,
) as (keyof typeof headingConfig.variants.size)[];

// Export the weight variants
export const HEADING_WEIGHTS = Object.keys(
  headingConfig.variants.weight,
) as (keyof typeof headingConfig.variants.weight)[];

// Export the tone variants
export const HEADING_TONES = Object.keys(
  headingConfig.variants.tone,
) as (keyof typeof headingConfig.variants.tone)[];

export const headingVariants = headingCva;
```



## Usage

Use the heading for page titles, section headers, and any semantic `h1`–`h6` text. Set `level` for
document outline semantics and `size` when the visual scale should differ from the default mapping.

```tsx
import Heading from "@/components/heading/heading";

export function Example() {
  return (
    <Heading level="h1" size="2xl">
      Page title
    </Heading>
  );
}
```

