Docs
Text

Text

Display text using well-defined typographic styles.

Sizes

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

Installation

Copy and paste the following code into your project.

import { cn } from "@/lib/utils"
 
// Define breakpoints and their corresponding min-widths for media queries
const breakpoints = {
  sm: "640px", // Example breakpoint min-widths
  md: "768px",
  lg: "1024px",
  xl: "1280px",
}
 
type BreakPoint = keyof typeof breakpoints
 
type TextSize = keyof typeof textSizes
 
interface TextProps {
  children: React.ReactNode
  size?: TextSize | { [key in BreakPoint]?: TextSize }
  transform?: React.CSSProperties["textTransform"]
  align?: React.CSSProperties["textAlign"]
  color?: string // TODO get better TS type here
  truncate?: boolean | number
  monospace?: boolean
  className?: string
  // TODO add the "as" property
}
 
const Text: React.FC<TextProps> = ({
  children,
  size = 14,
  transform,
  align,
  color,
  truncate,
  monospace,
  className,
}) => {
  const isMediaSize = typeof size === "object"
 
  const style: React.CSSProperties = isMediaSize
    ? Object.entries(size).reduce(
        (acc, [breakpoint, value]) => {
          acc[`--${breakpoint}-text-size`] = textSizes[value].fontSize
          acc[`--${breakpoint}-text-weight`] = textSizes[value].fontWeight
          acc[`--${breakpoint}-text-letter-spacing`] =
            textSizes[value].letterSpacing
          acc[`--${breakpoint}-text-line-height`] = textSizes[value].lineHeight
          return acc
        },
        {} as Record<string, string>
      )
    : {
        "--text-size": textSizes[size as TextSize]?.fontSize,
        "--text-weight": textSizes[size as TextSize]?.fontWeight,
        "--text-letter-spacing": textSizes[size as TextSize]?.letterSpacing,
        "--text-line-height": textSizes[size as TextSize]?.lineHeight,
      }
 
  if (transform) {
    // @ts-ignore-line
    style["--text-transform"] = transform
  }
 
  if (align) {
    // @ts-ignore-line
    style["--text-align"] = align
  }
 
  // @ts-ignore-line
  style["--text-color"] = `var(--ds-${color ?? "gray-1000"})`
 
  if (truncate && typeof truncate === "number") {
    // @ts-ignore-line
    style["--text-clamp"] = truncate
  }
 
  return (
    <p
      className={cn(
        "[color:hsl(var(--text-color))] [text-transform:var(--text-transform)]",
        isMediaSize
          ? [
              size?.sm &&
                "sm:[font-size:var(--sm-text-size)] sm:[font-weight:var(--sm-text-weight)] sm:[letter-spacing:var(--sm-text-letter-spacing)] sm:[line-height:var(--sm-text-line-height)]",
              size?.md &&
                "md:[font-size:var(--md-text-size)] md:[font-weight:var(--md-text-weight)] md:[letter-spacing:var(--md-text-letter-spacing)] md:[line-height:var(--md-text-line-height)]",
              size?.lg &&
                "lg:[font-size:var(--lg-text-size)] lg:[font-weight:var(--lg-text-weight)] lg:[letter-spacing:var(--lg-text-letter-spacing)] lg:[line-height:var(--lg-text-line-height)]",
              size?.xl &&
                "xl:[font-size:var(--xl-text-size)] xl:[font-weight:var(--xl-text-weight)] xl:[letter-spacing:var(--xl-text-letter-spacing)] xl:[line-height:var(--xl-text-line-height)]",
            ]
          : "[font-size:var(--text-size)] [font-weight:var(--text-weight)] [letter-spacing:var(--text-letter-spacing)] [line-height:var(--text-line-height)]",
        monospace && "font-mono",
        align && "[text-align:var(--text-align)]",
        truncate && typeof truncate === "number"
          ? "line-clamp-[var(--text-clamp)]"
          : "truncate",
        className
      )}
      style={style}
    >
      {children}
    </p>
  )
}
 
export { Text }
 
const textSizes = {
  10: {
    fontSize: "0.625rem",
    lineHeight: "0.75rem",
    fontWeight: "400",
    letterSpacing: "initial",
  },
  12: {
    fontSize: "0.75rem",
    lineHeight: `1rem`,
    fontWeight: "400",
    letterSpacing: "initial",
  },
  14: {
    fontSize: "0.875rem",
    lineHeight: "1.25rem",
    fontWeight: "400",
    letterSpacing: "initial",
  },
  16: {
    fontSize: "1rem",
    lineHeight: "1.5rem",
    fontWeight: "400",
    letterSpacing: "initial",
  },
  20: {
    fontSize: "1.25rem",
    lineHeight: "1.5rem",
    fontWeight: "600",
    letterSpacing: "-0.020625rem",
  },
  24: {
    fontSize: "1.5rem",
    lineHeight: "2rem",
    fontWeight: "600",
    letterSpacing: "-0.029375rem",
  },
  32: {
    fontSize: "2rem",
    lineHeight: "2.5rem",
    fontWeight: "600",
    letterSpacing: "-0.049375rem",
  },
  48: {
    fontSize: "3rem",
    lineHeight: "3.5rem",
    fontWeight: "700",
    letterSpacing: "-0.066875rem",
  },
  ["heading-72"]: {
    fontSize: "4.5rem",
    lineHeight: "4.5rem",
    letterSpacing: "-4.32px",
    fontWeight: "600",
  },
  ["heading-64"]: {
    fontSize: "4rem",
    lineHeight: "4rem",
    letterSpacing: "-3.84px",
    fontWeight: "600",
  },
  ["heading-56"]: {
    fontSize: "3.5rem",
    lineHeight: "3.5rem",
    letterSpacing: "-3.36px",
    fontWeight: "600",
  },
  ["heading-48"]: {
    fontSize: "3rem",
    lineHeight: "3.5rem",
    letterSpacing: "-2.88px",
    fontWeight: "600",
  },
  ["heading-40"]: {
    fontSize: "2.5rem",
    lineHeight: "3rem",
    letterSpacing: "-2.4px",
    fontWeight: "600",
  },
  ["heading-32"]: {
    fontSize: "2rem",
    lineHeight: "2.5rem",
    letterSpacing: "-1.28px",
    fontWeight: "600",
  },
  ["heading-24"]: {
    fontSize: "1.5rem",
    lineHeight: "2rem",
    letterSpacing: "-0.96px",
    fontWeight: "600",
  },
  ["heading-20"]: {
    fontSize: "1.25rem",
    lineHeight: "1.625rem",
    letterSpacing: "-0.4px",
    fontWeight: "600",
  },
  ["heading-16"]: {
    fontSize: "1rem",
    lineHeight: "1.5rem",
    letterSpacing: "-0.32px",
    fontWeight: "600",
  },
  ["button-16"]: {
    fontSize: "1rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "500",
  },
  ["button-14"]: {
    fontSize: "0.875rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "500",
  },
  ["button-12"]: {
    fontSize: "0.75rem",
    lineHeight: "1rem",
    letterSpacing: "0px",
    fontWeight: "500",
  },
  ["label-20"]: {
    fontSize: "1.25rem",
    lineHeight: "2rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["label-18"]: {
    fontSize: "1.125rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["label-16"]: {
    fontSize: "1rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["label-14"]: {
    fontSize: "0.875rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["label-13"]: {
    fontSize: "0.8125rem",
    lineHeight: "1rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["label-12"]: {
    fontSize: "0.75rem",
    lineHeight: "1rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-24"]: {
    fontSize: "1.5rem",
    lineHeight: "2.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-20"]: {
    fontSize: "1.25rem",
    lineHeight: "2.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-18"]: {
    fontSize: "1.125rem",
    lineHeight: "1.75rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-16"]: {
    fontSize: "1rem",
    lineHeight: "1.5rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-14"]: {
    fontSize: "0.875rem",
    lineHeight: "1.25rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
  ["copy-13"]: {
    fontSize: "0.8125rem",
    lineHeight: "1.125rem",
    letterSpacing: "0px",
    fontWeight: "400",
  },
} as const satisfies Record<
  string | number,
  {
    fontSize: string
    fontWeight: string
    letterSpacing: string
    lineHeight: string
  }
>

Update the import paths to match your project setup.

Variants

heading 72

heading 64

heading 56

heading 48

heading 40

heading 32

heading 24

heading 20

heading 16

button 16

button 14

button 12

label 20

label 18

label 16

label 14

label 13

label 12

copy 24

copy 20

copy 18

copy 16

copy 14

copy 13

Responsive

The Evil Rabbit jumps.

Color

The Evil Rabbit jumps.

Modifiers

The Evil Rabbit jumpsover the quick brown fox Lawful Meerkat.

Polymorphic

<p> semantically, <h2> visually.

Truncate

The Evil Rabbit jumps.

Clamp

The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps. The Evil Rabbit jumps.

Align

The Evil Rabbit jumps.

The Evil Rabbit jumps.

The Evil Rabbit jumps.

Monospace

This is a sans-serif font.

This is a monospace font.