Skip to main content
Graphite UI

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.

Contract 3.0.1Kit · 4 sets · 66 variantsOpen in Figma

Live preview

Rendered by the component itself from the same generated tokens as the rest of the site.

Contract updatedTabs moved to a new minor version. Nothing in your code needs to change.

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.json
import { 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.

Contract updatedTabs moved to a new minor version. Nothing in your code needs to change.
  1. 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.
  2. TitleOptional
  3. 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.

Status: Info
Contract updatedTabs moved to a new minor version. Nothing in your code needs to change.
Status: Success
Snapshot matchesEvery component page agrees with the kit snapshot.
Status: Warning
Snapshot may be staleRe-extract it from Figma before trusting a drift result.
Status: Danger
Short message
Snapshot matchesSaved.
High contrast: Info
Contract updatedTabs moved to a new minor version. Nothing in your code needs to change.
High contrast: Danger
Actionable
Snapshot may be staleRe-extract it from Figma before trusting a drift result.
Callout: Info
Contract updatedTabs moved to a new minor version. Nothing in your code needs to change.
Callout: Warning
Snapshot may be staleRe-extract it from Figma before trusting a drift result.

API reference

Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.

Notification props
PropTypeDefaultNotes
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.
highContrastboolean—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 with role="status", which waits for a pause.
Icon
The status icon is wrapped in aria-hidden and coloured with the variant’s status role. It decorates the message and never carries it.
Keyboard
Without onClose or action, 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 axes and how they map to code
Kit axisValuesCodeHow it maps
StatusSuccess · Error · Warning · InfovariantOne to one, except that the kit’s Error is danger in code, the name every status role uses.
High contrastTrue · FalsehighContraston-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 messageFalse · 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.
ActionableFalse · TrueactionA small ghost button in Body/3, centred in the top 48 row, 8 before the close. Its states are Button’s.
CloseBooleanonCloseA 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 iconBuilt invariant (icon overrides)Failed and Succeeded status icons, the warning triangle and fi-rs-info, at 16 and 20 as drawn.
CalloutSeparate setkind="callout"Info and Warning, High contrast and Long message; no close and no action.
ToastSeparate set—Its own component, with its own timing; carried on the plan for the remaining sets.