Alert
A contextual status message — an inline banner that surfaces feedback in place, with semantic roles, a built-in status glyph, an optional actions row, and one-line dismissal.Import
import { Alert } from "@hope-ui/components/alert";Alert is a compound component — a namespace object whose parts you compose. For the common case
you don't touch them (see Usage below); the full part tree is in the Anatomy.
Usage
For the common case, you don't touch the parts at all. Pass title, description, and a
colorScheme to Alert.Root and it auto-composes the anatomy for you — icon, content, title,
and description — picking the matching status glyph automatically.
A new version is ready to install.
<Alert.Root
colorScheme="info"
title="Update available"
description="A new version is ready to install."
/>Anatomy
The convenience props (title/description/icon/closable) are a shortcut: when Alert.Root
has no children, it auto-composes the parts below for you. Supply children and you take full
control of the structure — the convenience props are then ignored. Both paths produce the same
markup and the same accessibility wiring.
Auto-composed from title / description / icon props.
Built from Alert.Icon / Content / Title / Description.
<Alert.Root
colorScheme="info"
title="Convenience"
description="Auto-composed from title / description / icon props."
/><Alert.Root colorScheme="info">
<Alert.Icon>
<InfoIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>Compound</Alert.Title>
<Alert.Description>
Built from Alert.Icon / Content / Title / Description.
</Alert.Description>
</Alert.Content>
</Alert.Root>| Part | Element | Description |
|---|---|---|
Alert.Root | div | The alert surface and the state owner (open/dismiss, variant styling, ARIA wiring). Renders the live region. |
Alert.Icon | span | Wraps the leading glyph. Marked aria-hidden by default (decorative). |
Alert.Content | div | Column wrapper for the title, description, and actions. |
Alert.Title | div | The heading. Self-registers its id as the alert's aria-labelledby. |
Alert.Description | p | The body prose. Self-registers its id as the alert's aria-describedby. |
Alert.Actions | div | A flex row for action buttons, placed inside Alert.Content below the text. |
Alert.CloseTrigger | button | A CloseButton wired to dismiss the alert. Rendered automatically by the closable prop. |
Status
colorScheme sets the semantic role. The four status roles — info, success, warning, and
danger — each carry a built-in glyph, so omitting icon gives you the right one for free.
The color and glyph are reinforcing second channels; the meaning lives in the text.
A new workspace theme is available.
Your invoice is settled.
You've used 92% of your plan's quota.
The last build could not be published.
<Alert.Root variant="soft" colorScheme="info" title="Heads up" description="…" />
<Alert.Root variant="soft" colorScheme="success" title="Payment received" description="…" />
<Alert.Root variant="soft" colorScheme="warning" title="Storage almost full" description="…" />
<Alert.Root variant="soft" colorScheme="danger" title="Deployment failed" description="…" />primary and neutral — ship no built-in glyph. Pass an explicit icon (or set an app-wide default) when you use them, or leave the icon off entirely.Variants
The variant prop sets the visual treatment. default is a role-neutral raised surface whose
icon and title carry the role color (the body stays foreground); solid is a filled banner;
soft and subtle are tonal; outline is a hollow bordered notice.
A short description line.
A short description line.
A short description line.
A short description line.
A short description line.
<Alert.Root variant="default" colorScheme="info" title="default" description="…" />
<Alert.Root variant="solid" colorScheme="info" title="solid" description="…" />
<Alert.Root variant="soft" colorScheme="info" title="soft" description="…" />
<Alert.Root variant="subtle" colorScheme="info" title="subtle" description="…" />
<Alert.Root variant="outline" colorScheme="info" title="outline" description="…" />Sizes
Three sizes — sm, md (the default), and lg — scale the padding, gap, text, and the status
glyph together.
Compact density (sm).
Default density (md).
Roomy density (lg).
<Alert.Root size="sm" colorScheme="success" title="Small" description="…" />
<Alert.Root size="md" colorScheme="success" title="Medium" description="…" />
<Alert.Root size="lg" colorScheme="success" title="Large" description="…" />Icons
The icon prop overrides the role's default glyph per instance. It accepts any JSX — an inline
<svg> or an icon from your set. The glyph inherits currentColor, so a stroked SVG needs no color
of its own.
An explicit icon prop wins over the role default.
<Alert.Root
colorScheme="primary"
icon={<SparklesIcon />}
title="Now with sparkles"
description="An explicit icon prop wins over the role default."
/>Pass icon={false} to drop the glyph entirely — a text-only notice.
Just the message, no leading glyph.
<Alert.Root
variant="soft"
colorScheme="neutral"
icon={false}
title="No icon"
description="…"
/>Actions
For an alert the user can act on, add an Alert.Actions row. Because actions belong with the copy
(not the icon), place it inside Alert.Content, below the description. This is the point where
the convenience props give way to the compound anatomy.
Upgrade now to keep your projects, integrations, and history.
<Alert.Root colorScheme="warning">
<Alert.Icon>
<WarningIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>Your trial ends in 3 days</Alert.Title>
<Alert.Description>
Upgrade now to keep your projects, integrations, and history.
</Alert.Description>
<Alert.Actions>
<Button variant="solid" colorScheme="warning" size="sm">
Upgrade plan
</Button>
<Button variant="ghost" colorScheme="warning" size="sm">
Remind me later
</Button>
</Alert.Actions>
</Alert.Content>
</Alert.Root>On a solid alert
A solid alert is a filled, role-colored banner, so a solid action button would blend into it.
Reach for the Button inverted variant instead — a
contrasting fill built to stay legible on a solid, colored surface.
Reload to get the latest features and fixes.
<Alert.Root variant="solid" colorScheme="info">
<Alert.Icon>
<InfoIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>A new version is available</Alert.Title>
<Alert.Description>Reload to get the latest features and fixes.</Alert.Description>
<Alert.Actions>
<Button variant="inverted" colorScheme="info" size="sm">
Reload
</Button>
<Button variant="inverted" colorScheme="neutral" size="sm">
Later
</Button>
</Alert.Actions>
</Alert.Content>
</Alert.Root>Dismissible
Set closable to render an Alert.CloseTrigger in the corner. Dismissing plays the exit transition
(a fade and slide), then unmounts. Drive open as a controlled signal to bring it back; onExitComplete
fires once the exit animation has finished and the alert has left the DOM.
Dismiss me — I fade and slide out.
const [open, setOpen] = createSignal(true);
<Alert.Root
open={open()}
onOpenChange={setOpen}
closable
variant="soft"
colorScheme="success"
title="Changes saved"
description="Dismiss me — I fade and slide out."
/>;Left uncontrolled, an alert manages its own open state: it starts open (defaultOpen is true) and
closable dismisses it on click.
<Alert.Root closable colorScheme="success" title="Saved" description="…" />prefers-reduced-motion — it drops to an instant unmount when the user has reduced motion enabled. And because Alert.CloseTrigger renders a themed CloseButton, a closable alert needs a <ThemeProvider> ancestor (as every styled hope-ui component does).Live region & role
An alert is a live region: assistive tech announces its content when it appears. The role prop
picks the politeness.
| role | ARIA | When to use |
|---|---|---|
"alert" | role="alert" | Assertive — announced immediately, interrupting the user. The default; for errors and time-sensitive messages. |
"status" | role="status" | Polite — announced at the next opportunity, without interrupting. For confirmations and passive updates. |
"none" | — | No role — a purely visual notice that is not announced. For decorative or redundant messaging. |
<Alert.Root role="status" colorScheme="success" title="Saved" description="…" />Polymorphism
Render Alert.Root (or any part) as a different element or component with the render prop — a
function that receives the computed props and spreads them onto your element. There is no as
prop; render is the single polymorphism API.
Root is a <section> here, keeping all of Alert's props and styling.
<Alert.Root
variant="soft"
colorScheme="info"
title="Rendered as a section"
description="…"
render={(props) => <section {...props} />}
/>Theming
Alert's look comes from the active preset's recipe. You can override it at three levels, applied in
order (later wins a Tailwind conflict): recipe base → preset slotClasses → instance slotClasses
→ class.
Parts
Every part carries a data-slot attribute you can target, and each is addressable by name through
slotClasses.
| Slot | data-slot | Description |
|---|---|---|
root | alert | The alert surface (a div by default). |
icon | alert-icon | The span wrapping the glyph. Sizes the SVG per size; colored per variant. |
content | alert-content | The column wrapping title, description, and actions. |
title | alert-title | The heading line. |
description | alert-description | The body prose. |
actions | alert-actions | The action-button row. |
closeTrigger | alert-close-trigger | Placement of the dismiss button (chrome comes from CloseButton). |
Overriding one alert
class merges onto the root slot (your utilities win conflicts). slotClasses targets any slot by
name. Use literal class strings so your Tailwind build can see them.
A thicker leading rule and squared corners.
<Alert.Root
variant="soft"
colorScheme="info"
class="rounded-none border-s-4 border-info"
slotClasses={{ title: "uppercase tracking-wide" }}
title="Custom accent"
description="A thicker leading rule and squared corners."
/>App-wide defaults & overrides
Set defaults and global part classes for every Alert through the theme with definePreset, then
pass the derived preset to ThemeProvider. defaultProps are resolved at instance ?? preset ??
builtin precedence, so an explicit prop on a single alert always wins.
Soft & square by default.
Soft & square by default.
import { definePreset } from "@hope-ui/theming";
import { hope } from "@hope-ui/presets/hope";
export const myPreset = definePreset(hope, {
components: {
alert: {
// Every recipe variant is defaultable.
defaultProps: { variant: "soft" },
// Global part classes, folded in before per-instance slotClasses.
slotClasses: { root: "rounded-none" },
},
},
});The status glyphs are defaultable app-wide too — but as factories (() => JSX.Element), never a
bare element. A preset value is one object shared by every instance, and a built Solid node would
move between them; a factory is called fresh per instance. Each role has its own key:
infoIcon, successIcon, warningIcon, dangerIcon.
definePreset(hope, {
components: {
alert: {
// A factory, not <MyCheck /> — reuse-safe across every instance.
defaultProps: { successIcon: () => <MyCheck /> },
},
},
});Defaultable through defaultProps: variant, colorScheme, size, and the four status-glyph
factories. Per-usage props — title, description, icon, closable, open, role, and event
handlers — are intentionally not defaultable app-wide.
API
Alert.Root
Alert.Root accepts every native <div> attribute (except role and title, which are re-declared
below) in addition to the props below.
| Prop | Default | Type |
|---|---|---|
variant | "default" | AlertVariantVisual style: default, solid, soft, subtle, outline. default is a role-neutral surface whose icon + title carry the role color. |
colorScheme | "primary" | AlertColorSchemeSemantic role: primary, neutral, info, success, warning, danger. info/success/warning/danger carry a built-in glyph; primary/neutral ship none. |
size | "md" | AlertSizeDensity scale: sm, md, lg. Scales padding, gap, text, and the glyph together. |
role | "alert" | "alert" | "status" | "none"Live-region politeness. alert is assertive, status is polite, none renders no role (a purely visual notice). |
title | — | JSX.ElementConvenience: the alert title. Auto-composed into Alert.Title when Root has no children. |
description | — | JSX.ElementConvenience: the body. Auto-composed into Alert.Description when Root has no children. |
icon | role default | JSX.Element | falseConvenience: the leading glyph. false hides it; omit it to fall back to the preset {role}Icon default, then hope's built-in status glyph. |
closable | false | booleanRenders an Alert.CloseTrigger dismiss button. Requires a <ThemeProvider> ancestor. |
open | — | booleanControlled open state. Leave unset for uncontrolled (defaults to defaultOpen). |
defaultOpen | true | booleanInitial open state when uncontrolled. |
onOpenChange | — | (open: boolean) => voidCalled whenever the open state should change (e.g. a dismiss click). |
onExitComplete | — | () => voidFires after the exit transition finishes and the alert has unmounted. |
render | — | (props) => JSX.ElementRender Alert.Root as another element or component. Receives Root's computed props. The only polymorphism mechanism — there is no as prop. |
class | — | stringExtra classes merged onto the root slot; your utilities win conflicts via tailwind-merge. |
slotClasses | — | SlotClasses<"alert">Per-slot class overrides, keyed by root, icon, content, title, description, actions, closeTrigger. |
children | — | JSX.ElementThe compound anatomy (Alert.Icon / Content / …). When set, the convenience props are ignored. |
Parts
Alert.Icon, Alert.Content, Alert.Title, Alert.Description, and Alert.Actions each accept
their native element attributes plus a render prop. Alert.CloseTrigger accepts every
CloseButton prop; its dismiss handler is pre-wired (call
event.preventDefault() in your own onClick to cancel the close).
Accessibility
Alert.Root renders a role="alert" (or role="status") live region, so its message is
announced to assistive tech when it appears. The title and description are wired to the region as its
accessible name and description automatically.
- Live regions announce changes, not initial content. An alert present at first paint is not announced. Render the alert in response to the event (conditionally, after the action) so it is inserted into a region that already exists.
- Choose politeness deliberately.
role="alert"interrupts the user — reserve it for errors and time-sensitive messages. Userole="status"for confirmations and passive updates, androle="none"for a purely visual notice that shouldn't be announced. - Never rely on color alone. Each
colorSchemeis a distinct token, but color is a second channel, not the message (WCAG 1.4.1). The status glyph is decorative (aria-hidden), so the meaning must live in the title and description text. - The dismiss button is labeled.
Alert.CloseTriggeris aCloseButton, which self-labels with a localized"Close"accessible name and is fully keyboard-operable (Enter and Space). - Give a custom icon its meaning in text, not the glyph. Because the icon is
aria-hidden, swapping it never changes what a screen reader hears — keep the title and description carrying the message.