Title
The heading atom. Four sizes, all semibold, all mapped to type-scale tokens: small (text-sm), default (text-base), medium (text-xl), large (text-2xl). Two optional icon slots — left for the subject or a back control, right for a quiet help affordance.
Anatomy
Payment methods
- 1Left icon slot
Optional. The subject icon of the section, or a back control on a detail page. Rendered text-muted-foreground, 16px.
- 2Text
The heading itself: font-semibold text-foreground, sentence case. The only element in foreground — it carries the weight. Truncates with min-w-0 so a long title never pushes the icons out of the row.
- 3Right icon slot
Optional. Quiet help affordance, almost always an Info wrapped in a Tooltip. Same text-muted-foreground, 16px as the left slot.
- 4Row
flex items-center with a frame that never changes: gap-3 (12px) between the text and either icon, icons shrink-0 and locked at 16px, and no padding of its own so the leading edge is flush.
Sizes
Four steps, one weight. Every size is font-semibold and uses a Tailwind scale token, never a px value: small = text-sm (14/20), default = text-base (16/24), medium = text-xl (20/28), large = text-2xl (24/32). tracking-tight kicks in from medium up, per the typography foundation. Only the type scale moves — gap and icon size are identical at every step, so the four sizes stay one family instead of four lookalikes. Pick the size by how much page the title governs, and pick the tag with `as` by document outline: two separate decisions.
Payment methods
size="small"·text-sm·14 / 20·font-semiboldPayment methods
size="default"·text-base·16 / 24·font-semiboldPayment methods
size="medium"·text-xl·20 / 28·font-semiboldPayment methods
size="large"·text-2xl·24 / 32·font-semibold<Title size="small" icon={<ArrowLeft weight="light" />} iconRight={<Info weight="light" />}>Payment methods</Title>
<Title size="default" icon={<ArrowLeft weight="light" />} iconRight={<Info weight="light" />}>Payment methods</Title>
<Title size="medium" icon={<ArrowLeft weight="light" />} iconRight={<Info weight="light" />}>Payment methods</Title>
<Title size="large" icon={<ArrowLeft weight="light" />} iconRight={<Info weight="light" />}>Payment methods</Title>Icon slots
Both slots take any ReactNode and lock it to 16px through the slot wrapper ([&_svg]:size-4), at every size. That means a bare Phosphor icon and a button wrapping one land on the same grid, and a large title doesn't drag oversized icons with it. Both slots render text-muted-foreground: the text is the only thing in foreground, so the icons frame the title instead of competing with it. An interactive slot (a back button) can lift to text-foreground on hover.
Payment methods
Payment methods
Payment methods
Payment methods
{/* Both slots */}
<Title size="medium" icon={<ArrowLeft weight="light" />} iconRight={<Info weight="light" />}>
Payment methods
</Title>
{/* Left only */}
<Title size="medium" icon={<ArrowLeft weight="light" />}>Payment methods</Title>
{/* Right only */}
<Title size="medium" iconRight={<Info weight="light" />}>Payment methods</Title>
{/* No icons */}
<Title size="medium">Payment methods</Title>No padding of its own
Title never adds padding around itself. Its text sits flush against the leading edge, so inside a card it lines up with the card title, the description and the fields below it instead of floating 8px in. Spacing between a Title and its siblings is the container's job: the CardHeader gap, a Separator, a flex gap. A heading that carries its own margin silently breaks the alignment of every layout it lands in.
Connection settings
Retry policy
Up to 3 attempts over 24 hours.
Capture mode
Automatic on authorization.
{/* Flush: the Title, the description and the next block share one axis */}
<Card>
<CardHeader>
<Title size="default" as="h3">Connection settings</Title>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<div className="flex flex-col gap-1">
<Title size="small" as="h4" iconRight={<Info weight="light" />}>Retry policy</Title>
<p className="text-sm text-muted-foreground">Up to 3 attempts over 24 hours.</p>
</div>
</CardContent>
</Card>Recipes
Ready-to-copy compositions covering the most common Yuno usages of this atom.
Detail pages: large size, back arrow on the left, Info on the right. The arrow is a real button inside the slot, so it is focusable and announced; the Info is decorative and paired with a Tooltip.
Credit card
Configure how this payment method behaves at checkout.
<Title
size="large"
as="h1"
icon={
<button
type="button"
aria-label="Back to payment methods"
className="flex items-center rounded-md transition-colors hover:text-foreground"
>
<ArrowLeft weight="light" />
</button>
}
iconRight={
<Tooltip>
<TooltipTrigger asChild>
<span tabIndex={0}><Info weight="light" aria-hidden="true" /></span>
</TooltipTrigger>
<TooltipContent>How this method is charged and settled.</TooltipContent>
</Tooltip>
}
>
Credit card
</Title>medium size to break a long page into named blocks. The Info explains what the section covers without spending a description line.
Routing rules
Section content goes here.
<Title size="medium" as="h2" iconRight={<Info weight="light" />}>
Routing rules
</Title>
<Separator className="my-4" />default size — the same step CardTitle uses, so a Title with icons drops into a CardHeader without changing the rhythm.
Authorization rate
<Card>
<CardHeader>
<Title size="default" as="h3" iconRight={<Info weight="light" />}>
Authorization rate
</Title>
<CardDescription>Last 30 days across all connections.</CardDescription>
</CardHeader>
<CardContent>…</CardContent>
</Card>small size for the sub-blocks of a card or panel, where the card already owns the default-size title. This is a heading, not a form Label — use Label when there's a control to point at.
Connection settings
Retry policy
Up to 3 attempts over 24 hours.
Capture mode
Automatic on authorization.
<Title size="small" as="h4" iconRight={<Info weight="light" />}>
Retry policy
</Title>Import
Copy this import line at the top of the file where you compose this atom.
import { Title } from "@/components/ui/title";Props
Everything else from the underlying HTML or Radix primitive is forwarded via ...props.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "small" | "default" | "medium" | "large" | "default" | Type scale step. small = text-sm (14), default = text-base (16), medium = text-xl (20), large = text-2xl (24). All four are font-semibold; medium and large add tracking-tight. Only the text scales — gap-3 (12px) and 16px icons are constant at every size. |
| as | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "div" | "h2" | The tag rendered. Pick it by document outline, not by size. Use div when the heading is purely decorative or already announced by a parent (DialogTitle, CardTitle). |
| icon | React.ReactNode | — | Left slot. Subject icon or a back control. Rendered text-muted-foreground and locked to 16px by the slot ([&_svg]:size-4). Pass a real <button> when it navigates. |
| iconRight | React.ReactNode | — | Right slot. Quiet help affordance, almost always Info + Tooltip. Same text-muted-foreground, 16px. Not for primary actions. |
| className | string | — | Merged last. Use it for layout (w-full, justify-between), not to override size, weight, or to add padding — Title stays flush by design and spacing belongs to the container. |
| ...props | React.HTMLAttributes<HTMLHeadingElement> | — | Everything else forwards to the heading element (id, onClick, aria-*). title is omitted to avoid clashing with the HTML attribute. |
When to use
- Naming a page, a section, a card, or a block inside a card.
- Any heading that needs a subject icon or a help affordance next to it.
- Detail pages that open with a back control before the title.
- Anywhere you were about to write text-xl font-semibold by hand.
When not to use
- Form-field captions — that's Label, which wires htmlFor to a control.
- The top of a standard page — use the PageHeader organism, it already composes the title.
- Body copy or descriptions — Title is semibold by definition, never use it for a paragraph.
- Table column headers — use the Table primitive's <th>.
- As a button — if the whole row is clickable, that's an Accordion trigger or a link, not a Title.
Usage
- Pick size by scope (page > section > card > block) and `as` by outline.
- Keep titles sentence case, like every other section title at Yuno.
- Wrap the right Info in a Tooltip, and mark it aria-hidden when the Tooltip already carries the text.
- Put a real <button> in the left slot when it navigates back — the slot sizes it for you.
- Don't override the size with a text-* class — add a step here instead of inventing one per screen.
- Don't drop the weight to font-medium — a Title is semibold, that's what separates it from a Label.
- Don't put actions in a Title. The right slot is help-only (Info + Tooltip): no buttons, no menus, no links, no collapse chevrons. Actions live in the page header, the card footer or a toolbar.
- Don't stack two Titles of the same size to fake a title + description — use CardDescription or a muted paragraph.
Related
Cross-links to atoms and patterns you may reach for next.
- CardCardTitle is the same default step. Use Title inside a CardHeader when the card title needs icons.
- Page headerThe full page-top organism (eyebrow + title + description + actions). Use it instead of a bare Title at the top of a page.
- LabelFor form-field captions. A Label points at a control; a Title names a region.
- TooltipWhat the right Info slot is almost always wrapped in.
- TypographyThe scale and the four weights these sizes come from.