Search

Jump to any page.

Brand

Section Header

Eyebrow, heading, copy and an optional action for the top of a section.

Research

How institutions keep their standing as the world changes.

Notes on governed execution, evaluation and Gulf Arabic in operations.

pnpm dlx shadcn@latest add @paragon/section-header
Brings in@paragon/eyebrowcn
registry/paragon/components/section-header.tsx
import * as React from "react"
import { cn } from "cn"

import { Eyebrow } from "@/registry/paragon/components/eyebrow"

/**
 * Eyebrow, heading and supporting copy for the top of a section,
 * with an optional trailing action such as a TextLink.
 */
function SectionHeader({
  eyebrow,
  title,
  description,
  action,
  serif = false,
  className,
  ...props
}: Omit<React.ComponentProps<"header">, "title"> & {
  eyebrow?: React.ReactNode
  title: React.ReactNode
  description?: React.ReactNode
  action?: React.ReactNode
  /** Set the heading in Newsreader instead of Geist. */
  serif?: boolean
}) {
  return (
    <header
      data-slot="section-header"
      className={cn("flex flex-col gap-6 md:flex-row md:items-end md:justify-between", className)}
      {...props}
    >
      <div className="flex max-w-2xl flex-col gap-4">
        {eyebrow ? <Eyebrow tone="muted">{eyebrow}</Eyebrow> : null}
        <h2
          className={cn(
            "text-balance",
            serif
              ? "font-serif text-title font-normal"
              : "text-heading font-medium md:text-[2.25rem] md:tracking-[-0.04em]"
          )}
        >
          {title}
        </h2>
        {description ? (
          <p className="max-w-xl text-lead text-pretty text-muted-foreground">{description}</p>
        ) : null}
      </div>
      {action ? <div className="shrink-0">{action}</div> : null}
    </header>
  )
}

export { SectionHeader }