Alert
A message that belongs to the page, in six tones. Info, success, warning and danger each draw their own icon, so it reads without colour.
Alert
server - 0 KBA message that belongs to the page, in six tones. Info, success, warning and danger each draw their own icon, so it reads without colour.
Your trial ends in three days
Try it
The code
import { Alert } from 'topclassui/alert'
<Alert title="Your trial ends in three days">
Deploys pause when it does. Adding a payment method turns them back on.
</Alert>Not a live region: it is page content. Pass role="alert" when it appears after load, or announce the event with Toast.
Every state
13 statesSoft
Solid
Outline
Primary
Neutral
Success
Warning
Danger
Info
Title only
No icon
With actions
Import from the package
import { Alert } from 'topclassui/alert'Install once:npm i topclassui@beta zod
Examples
- For a message that belongs to the page: a trial about to end, a failed deploy, a saved form. For something that has just happened, use a Toast; for a bar above the whole page, use a Banner.
primaryandneutraltake the info icon. Pass your owniconto replace it, oricon={null}for none.childrenis the description, so it can hold several paragraphs or a list.actionsputs buttons or links in a row under it.- Keep
actionson the soft variant: an unfilled Button on a solid fill falls below 4.5:1. - A long title, description or URL wraps inside the box instead of truncating.
Your trial ends in three days
import { Alert } from 'topclassui/alert'
/** The docs sample: the tone picks the warning icon, so the message reads without colour. */
export default function Demo() {
return (
<Alert tone="warning" title="Your trial ends in three days">
Deploys pause when it does. Projects stay readable, and adding a payment method turns
deploys back on.
</Alert>
)
}
Primary
Neutral
Success
Warning
Danger
Info
Primary
Neutral
Success
Warning
Danger
Info
Primary
Neutral
Success
Warning
Danger
Info
import { Alert } from 'topclassui/alert'
/** Every tone in every variant, so axe measures all eighteen cells in each mode. */
export default function Demo() {
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-3">
<Alert variant="soft" tone="primary" title="Primary">A new version is ready.</Alert>
<Alert variant="soft" tone="neutral" title="Neutral">Nothing has changed since Monday.</Alert>
<Alert variant="soft" tone="success" title="Success">The invoice was paid.</Alert>
<Alert variant="soft" tone="warning" title="Warning">The trial ends in three days.</Alert>
<Alert variant="soft" tone="danger" title="Danger">The last deploy failed.</Alert>
<Alert variant="soft" tone="info" title="Info">Maintenance starts at 22:00.</Alert>
</div>
<div className="flex flex-col gap-3">
<Alert variant="solid" tone="primary" title="Primary">A new version is ready.</Alert>
<Alert variant="solid" tone="neutral" title="Neutral">Nothing has changed since Monday.</Alert>
<Alert variant="solid" tone="success" title="Success">The invoice was paid.</Alert>
<Alert variant="solid" tone="warning" title="Warning">The trial ends in three days.</Alert>
<Alert variant="solid" tone="danger" title="Danger">The last deploy failed.</Alert>
<Alert variant="solid" tone="info" title="Info">Maintenance starts at 22:00.</Alert>
</div>
<div className="flex flex-col gap-3">
<Alert variant="outline" tone="primary" title="Primary">A new version is ready.</Alert>
<Alert variant="outline" tone="neutral" title="Neutral">Nothing has changed since Monday.</Alert>
<Alert variant="outline" tone="success" title="Success">The invoice was paid.</Alert>
<Alert variant="outline" tone="warning" title="Warning">The trial ends in three days.</Alert>
<Alert variant="outline" tone="danger" title="Danger">The last deploy failed.</Alert>
<Alert variant="outline" tone="info" title="Info">Maintenance starts at 22:00.</Alert>
</div>
</div>
)
}
Soft
Solid
Outline
import { Alert } from 'topclassui/alert'
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Alert variant="soft" title="Soft">A tint of the tone, for most messages.</Alert>
<Alert variant="solid" title="Solid">The full fill, for the one message that must not be missed.</Alert>
<Alert variant="outline" title="Outline">A line in the tone colour, on the page background.</Alert>
</div>
)
}
Your trial ends in three days
The last deploy failed
Two people are editing this page
import { Button } from 'topclassui/button'
import { Alert } from 'topclassui/alert'
/** Actions sit on the soft variant: an unfilled Button on a solid fill fails 4.5:1. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Alert
tone="warning"
title="Your trial ends in three days"
actions={(
<>
<Button size="sm" tone="warning" render={<a href="/billing" />}>Add a payment method</Button>
<Button size="sm" variant="outline" tone="warning">Remind me later</Button>
</>
)}
>
Deploys pause when it does. Projects stay readable.
</Alert>
<Alert
tone="danger"
title="The last deploy failed"
actions={(
<>
<Button size="sm" tone="danger">Retry the deploy</Button>
<Button size="sm" variant="outline" tone="danger" render={<a href="/logs" />}>Read the log</Button>
</>
)}
>
The build stopped at step 4 of 6. The site still serves the previous version.
</Alert>
<Alert
tone="info"
title="Two people are editing this page"
actions={<Button size="sm" variant="outline" tone="info">Show who</Button>}
/>
</div>
)
}
Saved
import { Alert } from 'topclassui/alert'
/** A title alone, then a description alone: the missing part leaves no gap behind. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Alert tone="success" title="Saved" />
<Alert tone="info">Changes are saved as you type.</Alert>
</div>
)
}
The import finished
All 1,204 rows were read. Three were skipped:
- Row 18 has no email address.
- Row 311 repeats row 310.
- Row 902 has a date in the future.
Fix them in the file and import it again.
import { Alert } from 'topclassui/alert'
/** The description is a div, so it holds paragraphs and a list as well as one sentence. */
export default function Demo() {
return (
<Alert tone="success" title="The import finished">
<p>All 1,204 rows were read. Three were skipped:</p>
<ul className="list-disc ps-5">
<li>Row 18 has no email address.</li>
<li>Row 311 repeats row 310.</li>
<li>Row 902 has a date in the future.</li>
</ul>
<p>Fix them in the file and import it again.</p>
</Alert>
)
}
Reminders are on
No icon
import { bell } from 'topclassui/icons/bell'
import { Svg } from 'topclassui/svg'
import { Alert } from 'topclassui/alert'
/** The first replaces the tone's icon with the caller's own; the second has none at all. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Alert icon={<Svg icon={bell} size="xs" className="mt-0.5" />} title="Reminders are on">
You will hear about every comment on this page.
</Alert>
<Alert icon={null} tone="neutral" title="No icon">
The text carries the meaning on its own.
</Alert>
</div>
)
}
The card was declined
import { Alert } from 'topclassui/alert'
/** An alert is page content. This one passes role="alert", so a screen reader announces it
* when it appears after the page has loaded; one already in the first HTML is not read out. */
export default function Demo() {
return (
<Alert role="alert" tone="danger" title="The card was declined">
Check the number and the expiry date, or use another card.
</Alert>
)
}
The deploy failed while uploading the static assets to the edge network
https://example.com/projects/topclassui/deployments/2026-10-07/logs/build-step-four-of-six.txt
import { Alert } from 'topclassui/alert'
const LOG_URL = 'https://example.com/projects/topclassui/deployments/2026-10-07/logs/build-step-four-of-six.txt'
/** Two narrow boxes: the long title and description wrap, and the unbroken URL breaks anywhere. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="w-64">
<Alert tone="danger" title="The deploy failed while uploading the static assets to the edge network">
The full log is at {LOG_URL}, and it stays there for thirty days.
</Alert>
</div>
<div className="w-64">
<Alert variant="outline" tone="warning" title={LOG_URL} />
</div>
</div>
)
}
تم الدفع
تنتهي الفترة التجريبية بعد ثلاثة أيام
فشل النشر الأخير
import { Button } from 'topclassui/button'
import { Alert } from 'topclassui/alert'
/** The drawn RTL alert, soft success, then a warning with actions and an outline danger, each icon at the start. */
export default function Demo() {
return (
<div dir="rtl" lang="ar" className="flex flex-col gap-3">
<Alert tone="success" title="تم الدفع">
وصلت الدفعة وأُرسل الإيصال إلى بريدك.
</Alert>
<Alert
tone="warning"
title="تنتهي الفترة التجريبية بعد ثلاثة أيام"
actions={(
<>
<Button size="sm" tone="warning">أضف وسيلة دفع</Button>
<Button size="sm" variant="outline" tone="warning">ذكّرني لاحقاً</Button>
</>
)}
>
تتوقف عمليات النشر عندها، وتبقى المشاريع قابلة للقراءة.
</Alert>
<Alert variant="outline" tone="danger" title="فشل النشر الأخير">
يعرض الموقع النسخة السابقة.
</Alert>
</div>
)
}
Props
Keyboard and accessibility
Nothing to operate: it is not interactive on its own.
- Alert has no role: it is page content, read in place, not a live region.
- A screen reader does not read out an alert that is already in the first HTML. Pass
role="alert"only when it is inserted after the page has loaded and must be announced. - The tone never carries the meaning alone: each of the four meaningful tones draws its own icon. Alert itself takes no focus; only the caller's
actionsdo.
Right to left
The icon sits at the inline start and the text and actions follow it; every spacing class is logical, so nothing is mirrored by hand.
Server and client
Renders on the server and ships no JavaScript.
Files: index.tsx.
On the chip: server - 0 KB.