Notification
An inline message about the state of the page or a task, in one of four statuses. It stays until the condition changes; for a message that should come and go on its own, this is the wrong component.
Live preview
Rendered by the component itself from the same generated tokens as the rest of the site.
<Notification
title="Contract updated"
body="Tabs moved to a new minor version. Nothing in your code needs to change."
onClose={() => setOpen(false)}
/>Installation
Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.
npx shadcn@latest add https://www.graphite-ui.com/r/notification.jsonimport { Notification } from '@/components/ui/notification'Anatomy
Only the body is required. The status icon comes with the variant, in its status colour, but it is decorative and hidden from assistive tech, so the title or body has to say the status in words. Title and message share a line while they fit and the message wraps under the title when they do not. Pass onClose for the 48px close in the top right.
- IconRequiredDrawn from the variant, as the kit draws one in every variant (Failed and Succeeded status icons, the warning triangle, fi-rs-info). The icon prop overrides it; nothing removes it.
- TitleOptional
- BodyRequired
Variants
Four statuses, each bound to a generated status role: its container for the fill, its base role for the edge, stripe and icon. Status hue is pinned per status and chroma follows the source, so danger still reads as danger whatever colour the header is set to. High contrast inverts the fill; Actionable adds a ghost action; Callout is the kit’s closeless form.
API reference
Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.
| Prop | Type | Default | Notes |
|---|---|---|---|
| variant | 'info' | 'danger' | 'warning' | 'success' | — | The kit's Status. Its Error is danger here, the name every status role uses. |
| kind | 'inline' | 'callout' | — | The kit's Notification - Inline and Notification - Callout sets. A callout has no close control and no action, and the kit draws it for info and warning only. |
| highContrast | boolean | — | The kit's High contrast. The fill inverts to on-background with background text and no edge. |
| action | { label: string; onClick: () => void } | — | The kit's Actionable. A small ghost button in Body/3 before the close control. |
| onClose | () => void | — | Optional. When set, a close button labelled "Dismiss notification" renders at the trailing edge and calls it. Without it the notification has no close control and lasts until the caller stops rendering it. |
Design tokens
Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.
on-surfaceTitle and message on every status container, as the kit binds them (D6 on #219). Swept across 288 sources, both modes, AA and AAA, the worst pair is 9.78:1.dangerIcon, 1px edge and 3px stripe on the danger variant.warningIcon, edge and stripe on the warning variant.successIcon, edge and stripe on the success variant.infoIcon, edge and stripe on the info variant.danger-containerFill on the danger variant; the stripe and icon on it in high contrast.warning-containerFill on the warning variant; the stripe and icon on it in high contrast.success-containerFill on the success variant; the stripe and icon on it in high contrast.info-containerFill on the info variant; the stripe and icon on it in high contrast.on-warningThe "!" on the warning triangle.on-warning-containerThe "!" on the warning triangle in high contrast.on-backgroundThe high-contrast fill.backgroundHigh-contrast text and close glyph.primary-containerThe action label in high contrast, standing in for the kit's inverse link. (The action label and close glyph are otherwise primary, the kit's link-primary and icon-interactive, drawn by Button's ghost style; that label clears AA on every container but falls to 6.34:1 at AAA for some sources. Recorded, not hidden.)textTitle at Title/5 SemiBold and message at Body/3.spacingThe 16 inset and icon gap, the 48 row, and the action's margins.radiusContainer corner.
Usage
The contract's prohibitions, written as the choices you will actually face.
Do
- Place it next to what it is about, in the flow of the page, and leave it there while the condition holds.
- Say the status in the title, in words: “Payment failed”, not just “Error”. A red source colour can make danger and primary look alike.
- Save danger for what the reader must act on now. It is announced as an alert and interrupts a screen reader mid-sentence.
- Stop rendering it when the condition changes, so a stale success message never outlives the thing it confirmed. Pass onClose when the reader may also dismiss it.
Don’t
- Use it as a toast that fades on a timer. The kit’s Toast is a separate set with its own timing.
- Hand-pick a status colour or restyle the container. Each variant uses its generated container role, the same rule as Tag.
- Let the icon or the colour be the only place the status appears.
- Stack several notifications about one problem. One per condition, near where it happens.
Accessibility
What the component does for you, and what it leaves to you.
- Roles
- Danger renders with
role="alert", which interrupts. Info, success and warning render withrole="status", which waits for a pause. - Icon
- The status icon is wrapped in
aria-hiddenand coloured with the variant’s status role. It decorates the message and never carries it. - Keyboard
- Without
onCloseoraction, nothing takes focus. The action and the close are each one tab stop; the close is named “Dismiss notification”, with Button’s ghost focus ring. Enter or Space dismisses. Escape does nothing: this is inline content, not an overlay, so there is no focus to trap or return. Once it closes, the button that held focus is gone, so move focus somewhere sensible in onClose. - Contrast
- Text is on-surface on each status container, as the kit binds it: swept across 288 sources in both modes, the worst pair is 9.78:1, clear of AAA. The action label is primary, which clears AA on every container but falls to 6.34:1 at AAA for some sources. High contrast is background on on-background.
- Colour
- Status is shown three ways: the container with its edge and stripe, the icon, and the words. Colour is never the only signal.
- Motion
- Nothing animates on entry or exit, so there is nothing for reduced motion to switch off.
Figma parity
The kit files Inline, Callout and Toast as three sets on one page, plus a set for the action button. The code covers Inline and Callout on every axis; Toast is its own component.
| Kit axis | Values | Code | How it maps |
|---|---|---|---|
| Status | Success · Error · Warning · Info | variant | One to one, except that the kit’s Error is danger in code, the name every status role uses. |
| High contrast | True · False | highContrast | on-background fill, background text, no edge. The kit’s inverse stripe, icon and link stops are not engine roles; the status and primary containers stand in, swept at 3:1 or better. The close glyph is background, not the kit’s primary. |
| Long message | False · True | — | Layout, not a variant. Title and message share a line while they fit and wrap when they do not, which is what the kit’s two variants show. |
| Actionable | False · True | action | A small ghost button in Body/3, centred in the top 48 row, 8 before the close. Its states are Button’s. |
| Close | Boolean | onClose | A 48px ghost icon button flush in the top right, glyph in primary. The kit’s glyph is a plus, a slip; built as a cross. |
| Status icon | Built in | variant (icon overrides) | Failed and Succeeded status icons, the warning triangle and fi-rs-info, at 16 and 20 as drawn. |
| Callout | Separate set | kind="callout" | Info and Warning, High contrast and Long message; no close and no action. |
| Toast | Separate set | — | Its own component, with its own timing; carried on the plan for the remaining sets. |
