UIDex

Alert

التنبيه

role="alert"

also calledinline alert، banner، callout، admonition، notice box، message bar، ألرت، تنبيه مضمّن، شريط تنبيه، بانر، تنويه، صندوق ملاحظة

An alert is a message that takes its own space in the page layout and stays there until something clear removes it: the error gets fixed, or the user presses dismiss. An inline alert goes in the content flow right beside the thing it describes, like the line under an email field saying the address is malformed. A banner runs across the top of a page or a section. It talks about the whole screen rather than one control, and it stays until someone closes it. A callout is editorial: a note or a warning inside an article or a docs page, with no user action behind it. None of the three is a toast, because a toast floats above the page and carries a timer that erases it, while an alert reserves room in the layout and pushes the content below it down. None of them is a modal either: a modal blocks the page and waits for a decision, while an alert lets the user carry on and ignore it.

If you called it…

"the red box under the field that says the email is wrong""the yellow strip across the top with an exclamation mark""the message that sits there until you close it""the blue note box inside the documentation""the warning bar that comes back every time I open the page"

Live specimen

Interact with the demo. Every part is real and numbered.

إعدادات الفريق

اشتراك الفريق ينتهي بعد ٣ أيام. جدّده من صفحة الفوترة.

اسم الفريقفريق التصميم

تنويه: تغيير الاسم لا يغيّر رابط المساحة.

RTLالحافّة الملوّنة بـ border-inline-start، فتنتقل مع الاتجاه وحدها

Anatomy: every part, named

Hover a row to locate it in the demo above.

Build prompt

Build an in-page alert component in three shapes: inline beside the field it belongs to, a banner across the top of the page or of one section, and an editorial callout inside prose. Reserve role="alert" for errors and for anything that stops the user, and use role="status" for every other message. Never print an alert into the HTML at first paint, since nobody is told about it, and if you use a general aria-live region, keep it mounted empty and write into it later, because a region created and filled in the same tick is missed by most screen readers. Give each alert an aria-hidden status icon, a title that says what happened, body text that gives the next step, and at most one action button. Only the banner is dismissible: put an aria-label on the close button, store the dismissal in localStorage or on the account, and move focus to a known element afterwards. Never pull focus into an alert that appears while the user is typing, and never lean on colour alone, since the words carry the meaning. Use logical properties on every line: border-inline-start for the coloured edge, padding-inline-start for the matching inset, inset-inline-end for a positioned close button, and text-align: start for the text, with no left, right, or margin-left anywhere. If you draw the edge with box-shadow instead, multiply the offset by a direction variable, because that property has no logical form. Wrap Latin file names and error codes inside Arabic text in <bdi>, and never mirror the status icons when the page flips.

How it behaves right-to-left

This section is ours alone.

The coloured edge

mirrors

The coloured rule that types the alert sits at the logical start, which is the right in Arabic. Write it as border-inline-start: 3px solid and pair it with padding-inline-start; border-left and padding-left both stay on the left after the flip, which leaves the text pressed against the right edge with no inset at all. If you paint that rule with an inset shadow instead, remember that box-shadow has no logical form: inset 3px 0 0 pushes the shadow right, so the bar lands on the left inner edge whatever the page direction. Multiply the offset by a direction variable, inset calc(3px * var(--dir)) 0 0, with --dir set to -1 under [dir="rtl"].

The icon and dismiss row

mirrors

Icon at the logical start, then the text, then the dismiss button at the logical end. A plain flex row arranges itself because the inline axis follows direction, so gap plus margin-inline-start: auto on the close button is the whole job. When the button is positioned instead, as it usually is on a wide banner, write inset-inline-end: 12px rather than right: 12px. Do not add flex-direction: row-reverse under [dir="rtl"] thinking you are fixing the order: the row already flipped once, and the second flip leaves the visual order disagreeing with DOM order and with the Tab path.

Status icons never mirror

never mirrors

The warning triangle, the exclamation mark, the i in a circle, and the check mark carry the same meaning in both directions, and when they are written as text characters rather than svg their Unicode Bidi_Mirrored property is No, so the text engine leaves them alone too. A blanket [dir="rtl"] svg { transform: scaleX(-1) } breaks exactly these and shows them back to front for nothing. The arrow in a "View details" action inside the alert is directional and does have to flip, so scope the transform to a class you put on arrows only.

Latin runs inside the message

never mirrors

Error messages are full of Latin runs: a file name, an email address, a code such as ERR_502. Drop one into an Arabic sentence and the bidi algorithm reorders the full stop or the brackets around it, so the period jumps to the start of the line or the code comes apart from its delimiters. Isolate each run with <bdi>, or with dir="ltr", since the HTML default style sheet gives both of those unicode-bidi: isolate. A CSS class carrying direction: ltr on its own isolates nothing: direction sets the base of the run, while isolation is what stops the neutral characters around it joining it, so add unicode-bidi: isolate alongside.

A banner portaled out of the tree

mirrors

A page banner is often injected at the end of <body> through a portal, and logical properties resolve against the element's own computed direction, which is inherited down the DOM tree rather than the React tree. If dir="rtl" lives on <div id="app"> instead of on <html>, the banner sits outside that subtree, computes as ltr, and paints border-inline-start on the left with inset-inline-end on the right while every line of the CSS is correctly logical. Put dir on <html>, or pass dir explicitly to the portal container.

In code

Each row is one framework's word for the same thing. Take the row your project speaks.

ARIArole="alert" / role="status"The first is assertive with aria-atomic="true" and cuts in; the second is polite and waits its turn.
HTML<output>The one native element that arrives as a live region already: its implicit role is status.
shadcn/ui<Alert> + <AlertTitle> + <AlertDescription>Renders a div with role="alert" and just two variants: default and destructive.
Material UI<Alert severity="error">Four severities, error, warning, info and success, and the root carries role="alert" by default.
Radix UI<AlertDialog>A near name for a different thing: a blocking dialog that waits for a decision. Radix has no inline Alert primitive.
Ant Design<Alert banner closable />The banner prop is exactly the difference between the two shapes: the same component drawn as a full-width strip.
CSSborder-inline-startThe logical property that moves the coloured edge to the correct side on its own.

See also

Updated · 2026-08-19