GitHub

Typography

Semantic text elements with consistent styling. Provides unified typography system for headings, body text, blockquotes, lists, and inline code.

AccessibleDark ModeSemantic11 VariantsFlexible

Install

$npx react-principles add typography
01

Live Demo

Explore all variants and interactive states in Storybook.

Open Storybookopen_in_new

Heading 1 - Page Title

Heading 2 - Section Title

Heading 3 - Subsection Title

Heading 4 - Component Title


This is body text. It uses a comfortable reading size with proper line height for long-form content. The text color provides good contrast in both light and dark modes.

This is a lead paragraph. It's larger than body text and perfect for introductory content or opening statements.

This is muted text. It's styled with a lighter color for secondary information.

This is small text. Use it for fine print, legal disclaimers, or copyright notices.

"Good typography is invisible—it lets the content shine without drawing attention to itself."
  • Semantic HTML elements by default
  • Consistent sizing and spacing
  • Dark mode support out of the box

You can use inline code like Typography within body text to highlight technical terms.

02

Code Snippet

src/ui/Typography.tsx
import { Typography } from "@/ui/Typography";

// Headings
<Typography variant="h1">Page Title</Typography>
<Typography variant="h2">Section Title</Typography>
<Typography variant="h3">Subsection Title</Typography>

// Body text
<Typography variant="p">Body text paragraph.</Typography>
<Typography variant="lead">Large introductory paragraph.</Typography>
<Typography variant="muted">Secondary subdued text.</Typography>

// Block elements
<Typography variant="blockquote">"Quote text here"</Typography>
<Typography variant="list">
  <li>First item</li>
  <li>Second item</li>
</Typography>

// Inline code
<Typography variant="code">const foo = "bar";</Typography>
03

Copy-Paste (Single File)

Typography.tsx
import { forwardRef, type HTMLAttributes } from "react";
import { cn } from "@/lib/utils";

// ─── Types ────────────────────────────────────────────────────────────────────

export type TypographyVariant =
  | "h1" | "h2" | "h3" | "h4"
  | "p" | "lead" | "muted" | "small"
  | "blockquote" | "code" | "list";

export interface TypographyProps extends Omit<HTMLAttributes<HTMLElement>, "as"> {
  variant?: TypographyVariant;
  as?: React.ElementType;
}

// ─── Constants ────────────────────────────────────────────────────────────────

const VARIANT_STYLES: Record<TypographyVariant, string> = {
  h1: "text-4xl font-black tracking-tight text-slate-900 dark:text-white md:text-5xl",
  h2: "text-2xl font-bold text-slate-900 dark:text-white",
  h3: "text-xl font-bold text-slate-900 dark:text-white",
  h4: "text-lg font-semibold text-slate-900 dark:text-white",
  p: "text-sm leading-relaxed text-slate-600 dark:text-slate-400",
  lead: "text-lg leading-relaxed text-slate-700 dark:text-slate-300",
  muted: "text-sm text-slate-500 dark:text-slate-400",
  small: "text-xs text-slate-500 dark:text-slate-400",
  blockquote: "border-l-4 border-primary pl-4 italic text-slate-700 dark:text-slate-300",
  code: "font-mono text-xs bg-slate-100 dark:bg-[#1f2937] px-1.5 py-0.5 rounded text-slate-900 dark:text-white",
  list: "list-disc pl-4 space-y-1 text-sm text-slate-600 dark:text-slate-400",
};

const DEFAULT_ELEMENTS: Record<TypographyVariant, string> = {
  h1: "h1", h2: "h2", h3: "h3", h4: "h4",
  p: "p", lead: "p", muted: "p", small: "small",
  blockquote: "blockquote", code: "code", list: "ul",
};

// ─── Component ────────────────────────────────────────────────────────────────

export const Typography = forwardRef<HTMLElement, TypographyProps>(
  function TypographyRoot({ variant = "p", as, className, children, ...rest }, ref) {
    const Component = as || DEFAULT_ELEMENTS[variant];
    const variantStyle = VARIANT_STYLES[variant];

    return (
      <Component ref={ref} className={cn(variantStyle, className)} {...rest}>
        {children}
      </Component>
    );
  }
);
04

Props

Extends all native HTML element attributes. The rendered element can be customized with the `as` prop.

PropTypeDefaultDescription
variantTypographyVariant"p"Typography style to apply (h1, h2, h3, h4, p, lead, muted, small, blockquote, code, list).
asReact.ElementTypeOverride the default HTML element. Example: variant='h2' as='h1' renders h1 with h2 styling.
classNamestringAdditional CSS classes to apply (merged with variant styles).
React Principles