Browse docs
Browse docs
Surface a persistent status. Flag a warning. Confirm a save.
import { Alert } from '@dashforge/tw';
<Alert severity="success">Customer saved.</Alert><Alert severity="info">Heads up: build will take ~3 minutes.</Alert>
<Alert severity="warning" onClose={() => dismiss()}>
Your trial ends in 5 days.
</Alert>
<Alert severity="danger" variant="filled">
<AlertTitle>Failed to save</AlertTitle>
Check the network and retry.
</Alert>Four tones, all token-driven through dashforgePreset(). Use danger, not error — the prop value aligns with the danger.* token palette name (see Design decisions).
import { Alert, Stack } from '@dashforge/tw';
<Stack gap={2}>
<Alert severity="info">Informational message.</Alert>
<Alert severity="success">Operation completed.</Alert>
<Alert severity="warning">Check the field above.</Alert>
<Alert severity="danger">Something went wrong.</Alert>
</Stack>The same 3-variant axis as <Snackbar> (which is the transient-toast sibling of Alert):
import { Alert, Stack } from '@dashforge/tw';
<Stack gap={2}>
<Alert severity="info" variant="standard">Standard (soft tinted, default).</Alert>
<Alert severity="info" variant="filled">Filled (solid bg + light text).</Alert>
<Alert severity="info" variant="outlined">Outlined (border only).</Alert>
</Stack>standard is the default — softly tinted background with same-color text. Suitable for non-urgent persistent messaging inside dashboards. Use filled for high-prominence callouts, outlined for low-visual-weight notices on busy backgrounds.
<AlertTitle> ships as a sub-component for the heading row. It renders as a semantically appropriate element with the right typography.
import { Alert, AlertTitle } from '@dashforge/tw';
<Alert severity="warning">
<AlertTitle>Heads up</AlertTitle>
Your subscription expires in 7 days. Renew to keep access to premium features.
</Alert>The icon prop is tristate:
undefined (omitted) → default SVG icon for the severity, from _shared/severity/ReactNode → custom icon (any React element)false → no icon at all<Alert severity="info" icon={<MyCustomInfoIcon />}>Custom icon.</Alert>
<Alert severity="info" icon={false}>No icon at all.</Alert>Pass onClose to render a close button on the right. The button has accessible aria-label="Close" by default; override with closeText.
import { useState } from 'react';
import { Alert, AlertTitle, Button } from '@dashforge/tw';
function DismissibleAlert() {
const [open, setOpen] = useState(true);
if (!open) return <Button variant="outline" onClick={() => setOpen(true)}>Show alert again</Button>;
return (
<Alert severity="warning" onClose={() => setOpen(false)}>
<AlertTitle>Heads up</AlertTitle>
Your trial ends in 5 days. Click X to dismiss.
</Alert>
);
}Custom right-side action (e.g. a CTA button). When action is set and onClose is also set, both render — action left of the close button.
<Alert
severity="warning"
action={<Button size="sm" variant="outlined">Renew now</Button>}
>
Your trial ends in 5 days.
</Alert>By default role resolves to 'alert' for danger and 'status' for everything else. Override when needed (e.g. 'alert' for a critical warning to interrupt screen-reader flow):
<Alert severity="warning" role="alert">
Unsaved changes will be lost.
</Alert>Alert ships the universal bridge contract from day one — same as <Button>, <TextField>, and the other interactive components (Sprint 4.4 alignment).
// RBAC gating
<Alert severity="danger" access={{ requires: 'workspace.delete', when: 'denied:hide' }}>
Workspace will be permanently deleted.
</Alert>
// Engine-reactive visibility
<Alert severity="warning" visibleWhen={(engine) => engine.getValue('hasUnsavedChanges') === true}>
Unsaved changes will be lost on navigation.
</Alert>Configure <Alert> defaults application-wide.
import { patchTheme } from '@dashforge/tw-theme';
patchTheme({
components: {
Alert: {
defaults: { variant: 'outlined', density: 'comfortable' },
},
},
});Configurable axes (AlertDefaultVariantProps):
| Axis | Type | Notes |
|---|---|---|
variant | 'standard' | 'filled' | 'outlined' | Visual treatment (tinted / solid / bordered). |
density | 'comfortable' | 'compact' | Vertical padding — compact tightens inline usage. |
severity is deliberately not theme-configurable — it is semantic per-alert (info/success/warning/danger), not visual identity. Same for icon, onClose, action, role, access, visibleWhen, event handlers.
Precedence chain (lowest → highest):
defaultVariants from the internal alertVariants recipe (density: 'comfortable') + component defaults (variant: 'standard').theme.components.Alert.defaults (application-wide).<Alert variant="filled" severity="danger" />) — wins over theme.sx — appended to the root and wins over conflicting classes via tailwind-merge.TypeScript: theme.components.Alert.defaults autocompletes to the two axes above.
Reactivity: useComponentDefaults('Alert') subscribes to the theme store — patchTheme re-renders every mounted instance inheriting the changed axis.
<Alert> props| Prop | Type | Default | Description |
|---|---|---|---|
severity | Severity | — | Visual severity. Drives the color treatment and the default ARIA role (alert for warning / danger, status for info / success).Note: this is danger, not MUI's error. The runtime behaviour is identical; the naming follows the Dashforge token palette. |
access | AccessRequirement | — | RBAC requirement. When the current subject does not satisfy the requirement, the alert is hidden (or disabled / read-only, per onUnauthorized). |
action | ReactNode | — | Custom trailing slot — CTA buttons, links, inline forms. When provided, replaces the auto-rendered close button. The consumer is responsible for wiring any close behaviour into the custom action node. |
children | ReactNode | — | Body content of the alert. |
className | string | — | Standard React className — appended to the root via cn(). |
closeText | string | 'Close' | aria-label for the close button. |
icon | ReactNode | false | — | Icon control with full MUI parity. - omitted / undefined → default per-severity icon (lib's inline stroke SVG) - ReactNode → consumer-provided custom icon (Lucide, Phosphor, Tabler, custom SVG — bring your own iconography) - false → no icon rendered (the colored surface carries the severity signal; use when icons compete with the layout) |
onClose | () => void | — | When defined, the alert renders a trailing close button that fires this callback on click. Ignored if action is provided (action slot wins, matching MUI behaviour). |
role | 'alert' | 'status' | — | Override the auto-derived ARIA role. Defaults to 'alert' for severity={'warning' | 'danger'} (assertive announcement) and 'status' for severity={'info' | 'success'} (polite). |
slotProps | AlertSlotProps | — | Per-slot overrides — typed handles for the inner elements. |
sx | ClassValue | — | Root-element class shortcut (string or clsx-compatible value). |
variant | SeverityVariant | 'standard' | Variant of the severity surface. Mirrors MUI's three-way axis. - 'standard' (default) — tinted soft surface, severity-toned text. The "all-purpose" reading. - 'filled' — solid colored surface, light text. High visual weight, for blocking / critical messages. - 'outlined' — transparent surface, severity border + text. Minimal weight, for dense layouts. |
visibleWhen | (engine: Engine) => boolean | — | Reactive visibility predicate. Re-evaluated on every engine state change when the alert is mounted inside a <DashForm>; outside a form, evaluated as a plain predicate (the consumer captures any external state in the closure).When the predicate returns false, the component renders null — same contract as form fields. |
<AlertTitle> props| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The heading text. |
className | string | — | Merged via tailwind-merge. |
<Alert> is a compound component with 6 named slots. Each slot accepts a ComponentPropsWithoutRef<...>-shaped override via slotProps:
| Slot | Element | Purpose |
|---|---|---|
root | div | Outer surface carrying severity + variant color classes. |
icon | span | Leading severity icon container. |
titleSlot | div | The <AlertTitle> heading, when composed as a child. |
content | div | Main body text container (flex-grow). |
action | div | Right-side custom action node (action prop). |
closeButton | button | Auto-rendered close × button when onClose is set. |
<Alert
severity="warning"
onClose={dismiss}
slotProps={{
icon: { className: 'text-warning-800' },
content: { className: 'font-medium' },
closeButton: { className: 'opacity-100 hover:bg-warning-100' },
}}
>
<AlertTitle>Renew soon</AlertTitle>
Your trial ends in 3 days.
</Alert>Use sx for a root-level class override; use slotProps when you need to reach a specific inner element (e.g. bump close button opacity, tighten the content font).
severity="danger" vs MUI's "error" is intentional — the prop value aligns with the danger.* token palette. See Design decisions → severity rename._shared/severity/, shared with <Snackbar>. A future <Banner> will plug into the same foundation.<Snackbar>. Alert is for persistent inline status.@dashforge/forms engine + @dashforge/rbac package as the form fields, so visibleWhen predicates and access declarations are portable across components and across MUI/TW flavors.