uiatom
Eyebrow
The small label above a section heading. It is a paragraph, not a heading.
Preview
Installation
pnpm dlx shadcn@latest add https://facadeui.dev/r/eyebrow.jsonThis component needs utils. The CLI installs them for you.
Usage
This is the code for the preview above. To install it as a file, run npx shadcn@latest add @facade/eyebrow-demo.
import { Eyebrow } from "@registry/ui/eyebrow"
import { Heading } from "@registry/ui/heading"
export function Demo() {
return (
<div className="flex flex-col gap-8">
<div className="flex flex-col gap-2">
<Eyebrow>Platform</Eyebrow>
<Heading level={2} className="text-display-sm font-semibold">
One place for everything
</Heading>
</div>
<div className="flex flex-col gap-2">
<Eyebrow tone="primary">Changelog</Eyebrow>
<Heading level={2} className="text-display-sm font-semibold">
Shipped this week
</Heading>
</div>
</div>
)
}Source
These are the files the CLI copies into your project.
/**
* Eyebrow — the small label that sits above a section heading.
*
* The `primary` tone puts the brand colour in a tick, not in the letters: a
* brand colour need only clear 3:1 as a shape, but 4.5:1 as 14px text.
*
* a11y: never a heading. An eyebrow reads as a category, not as an outline
* level, and promoting it to `<h3>` above an `<h2>` would invert the document
* structure for screen-reader users navigating by heading. It renders a `<p>`
* by default, or a `<span>` when it is already inside flow text. The tick is a
* pseudo-element, so it is not announced.
*
* Dependencies: react, @/lib/utils.
*/
import type { ComponentPropsWithoutRef, ElementType, ReactNode } from "react"
import { cn } from "@/lib/utils"
export interface EyebrowProps extends Omit<ComponentPropsWithoutRef<"p">, "children"> {
as?: "p" | "span" | "div"
/** `muted` is the default; `primary` leads with a tick in the brand colour. */
tone?: "muted" | "primary" | "foreground"
children?: ReactNode
}
const tones: Record<NonNullable<EyebrowProps["tone"]>, string> = {
muted: "text-muted-foreground",
// Inline, so the tick follows the text's alignment and its first line.
primary:
"text-foreground before:bg-primary before:mr-[0.75em] before:inline-block before:size-[0.6em] before:rounded-[0.125em] before:content-['']",
foreground: "text-foreground",
}
export function Eyebrow({
as = "p",
tone = "muted",
className,
children,
...props
}: EyebrowProps) {
const Component = as as ElementType
return (
<Component
className={cn(
"text-sm font-semibold uppercase tracking-[0.12em]",
tones[tone],
className,
)}
{...props}
>
{children}
</Component>
)
}Props
EyebrowProps
Extends Omit<ComponentPropsWithoutRef<"p">, "children">.
| Prop | Type | Default |
|---|---|---|
as | "p" | "span" | "div" | "p" |
tone`muted` is the default; `primary` leads with a tick in the brand colour. | "muted" | "primary" | "foreground" | "muted" |
children | ReactNode | — |