hope-uiearly-preview

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.

<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.

Alert.Root
├── Alert.Icon
├── Alert.Content
│ ├── Alert.Title
│ ├── Alert.Description
│ └── Alert.Actions
└── Alert.CloseTrigger auto · closable
Convenience — Root auto-composes
<Alert.Root
  colorScheme="info"
  title="Convenience"
  description="Auto-composed from title / description / icon props."
/>
Compound — you compose the parts
<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>
PartElementDescription
Alert.RootdivThe alert surface and the state owner (open/dismiss, variant styling, ARIA wiring). Renders the live region.
Alert.IconspanWraps the leading glyph. Marked aria-hidden by default (decorative).
Alert.ContentdivColumn wrapper for the title, description, and actions.
Alert.TitledivThe heading. Self-registers its id as the alert's aria-labelledby.
Alert.DescriptionpThe body prose. Self-registers its id as the alert's aria-describedby.
Alert.ActionsdivA flex row for action buttons, placed inside Alert.Content below the text.
Alert.CloseTriggerbuttonA 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.

<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="…" />

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.

<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.

<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.

<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.

<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.

<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.

<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.

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.

Uncontrolled — dismisses itself
<Alert.Root closable colorScheme="success" title="Saved" description="…" />

Live region & role

An alert is a live region: assistive tech announces its content when it appears. The role prop picks the politeness.

roleARIAWhen 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.

Render Root as a section
<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 slotClassesclass.

Parts

Every part carries a data-slot attribute you can target, and each is addressable by name through slotClasses.

Slotdata-slotDescription
rootalertThe alert surface (a div by default).
iconalert-iconThe span wrapping the glyph. Sizes the SVG per size; colored per variant.
contentalert-contentThe column wrapping title, description, and actions.
titlealert-titleThe heading line.
descriptionalert-descriptionThe body prose.
actionsalert-actionsThe action-button row.
closeTriggeralert-close-triggerPlacement 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.

<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.

theme.ts
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.

Swap the default success glyph
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.

PropDefaultType
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.
iconrole 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.
closablefalse
booleanRenders an Alert.CloseTrigger dismiss button. Requires a <ThemeProvider> ancestor.
open
booleanControlled open state. Leave unset for uncontrolled (defaults to defaultOpen).
defaultOpentrue
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. Use role="status" for confirmations and passive updates, and role="none" for a purely visual notice that shouldn't be announced.
  • Never rely on color alone. Each colorScheme is 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.CloseTrigger is a CloseButton, 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.