GrAlert
Shows an important message, warning or action status.
Overview
When to take it
- the message belongs to a place on the page — a warning above a form, an explanation inside a section: it lives where its cause lives;
- the message has to stay — a toast leaves on its own, this one is read for as long as it takes;
- there is an action inside — the actions slot holds “Retry”, “Open settings”;
- the message appears asynchronously —
liveannounces it to a screen reader instead of leaving it silent.
When to take something else
| Need | Take |
|---|---|
| A short message about the result of an action | GrToaster |
| A server error with a status and details | GrResponseErrorBanner |
| An error on a single field | GrFormField |
| The screen is empty and that needs explaining | GrEmptyState |
| An answer from the user is required | GrConfirmDialog |
Variants every tone and view, rendered by the real component
tone \ variant | soft | outline |
|---|---|---|
primary | ||
neutral | ||
success | ||
warning | ||
danger | ||
info | ||
slate | ||
azure |
The grid is live: hover and press it. Hover, focus and active states are not drawn here — they belong to the browser, not to a prop.
Playground controls come from the API, not from hand
Loading…
0 changed· state is in the URL
<GrAlert title="Invoices come from a new address">From 1 November they are sent from [email protected] — add it to your contacts.</GrAlert>Examples 6 each with a live demo and its code
A warning next to its cause
The message stands in the billing card, not in a corner of the screen, and stays until it is dealt with — unlike a toast. The title is the fact, the text is the consequence, and the
#actionsslot puts the ways out under the text. «Remind me in a week» swaps the warning for aninfonote of the same shape.BillingBusiness plan · 18 seatsActiveYour card expires in 12 daysVisa ending 4242 expires on 31 October. The November invoice of €522.00 will fail without a new card.Next invoice1 November · €522.00Payment methodVisa •••• 4242 · expires 10/26A result the screen reader hears
One alert whose words change with the outcome of the sync: a live region announces a change of its content, while a freshly inserted one may go unheard. With
live="auto"the tone picks the role —warninganddangerinterrupt,successwaits for a pause. Run the sync a few times: the service answers differently.Fabrikam Books ConnectedInvoices and payments sync every hour.Last sync 2 hours ago214 invoices and 61 payments are in Fabrikam Books.Tone, weight and an icon that names the subject
Tone and variant are separate axes: the incident is
dangeron a tinted background, planned work isoutlineand does not compete with it.#iconswaps the glyph for the subject — a card, a rocket, a clock. Notices that load with the page are content, not events, so the incident getslive="off".System statusUpdated 2 minutes agoPartial outageCard payments are delayedCharges go through, but receipts arrive up to 20 minutes late. We are working on it with the payment provider.Release 2026.10.6 is liveFaster exports and the new invoice editor are on for every workspace.Maintenance on Saturday, 11 October02:00–03:00 UTC. Sign-in and the API stay up; exports pause for about ten minutes.Two ways to close
With
v-model:visiblethe cross hides the message and nobody else has to know. With only@closeit is a request: the alert stays, and the screen decides — here it asks first, because turning summaries off changes the workspace for everyone.New: export to ExcelNumber formats and formulas survive the export. Find it under Reports → Export.AI summaries are onEvery invoice and report opens with a three-line summary.
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
tone |
| undefined | The meaning of the message: the colour of the background and the border, the icon glyph and — with `live="auto"` — the role for a screen reader. `warning` and `danger` interrupt speech, the others wait for a pause. `info` by default; globally — `componentDefaults`. |
variant | "soft" | "outline" | undefined | undefined | The weight: `soft` is a tinted background, `outline` is only a border in the tone, for calm notes next to other messages. `soft` by default. |
title | string | undefined | undefined | A short fact on the first line: «Your card expires in 12 days». The details go into the text below it; without a title the message is one line of text. |
closable | boolean | undefined | undefined | A close button. It does not hide the message by itself: it emits `close` and `update:visible`, and the screen decides whether to hide it (see `visible`). |
live | GrAlertLive | undefined | undefined | How the message is announced to a screen reader: `auto` — by tone, `assertive` — `role="alert"`, `polite` — `role="status"`, `off` — no role, when the message is already announced another way. `auto` by default. |
icon | boolean | undefined | true | Whether to show the tone icon. An icon of your own goes into the `#icon` slot; the prop is for the case where the icon gets in the way: a narrow column, a dense list, a message inside a form. |
visiblev-model | boolean | undefined | true | The visibility of the message — **controlled only**: without the prop the alert is always visible, and closing stays the concern of the consumer (`@close`). With `v-model:visible` the component hides itself. The prop deliberately has no state of its own. It would turn the close button into an irreversible action for everyone who already lives on `@close` and, for instance, asks for confirmation there. |
backgroundColor | string | undefined | undefined | A background instead of the tone — the colour of a brand or a partner. The layout, the icon and closing stay the same. The `--gr-alert-bg` variable does the same from CSS. |
textColor | string | undefined | undefined | The colour of the text, the title and the icon instead of the tone (`--gr-alert-*` in `tokens.md`). |
borderColor | string | undefined | undefined | The colour of the border instead of the tone; with `outline` it is the main colour of the message. |
Slots
| Slot | Type | Description |
|---|---|---|
default | any | The text of the message. |
icon | any | An icon instead of the glyph chosen by tone. Decorative: it stays `aria-hidden`. |
actions | any | Actions on the message: "Retry", "Details". They go under the text. |
Events
| Event | Signature | Description |
|---|---|---|
close | (event: "close"): void | — |
update:visible | (event: "update:visible", value: boolean): void | — |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrAlertTone, GrAlertLive, GrAlertProps } from '@feugene/granularity/components/GrAlert'Filedist/types/components/GrAlert/config.d.ts
const grAlertConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrAlert">;Filedist/types/components/GrAlert/GrAlert.vue.d.ts
type GrAlertTone = GrTone;type GrAlertLive = 'auto' | 'assertive' | 'polite' | 'off';interface GrAlertProps {
tone?: GrAlertTone;
variant?: GrAlertVariant;
title?: string;
closable?: boolean;
live?: GrAlertLive;
icon?: boolean;
visible?: boolean;
backgroundColor?: string;
textColor?: string;
borderColor?: string;
}interface GrAlertEmits {
(e: 'close'): void;
(e: 'update:visible', value: boolean): void;
}Filedist/types/components/GrAlert/defaults.d.ts
interface GrAlertConfigurableProps {
tone: GrTone;
variant: GrAlertVariant;
closable: boolean;
live: GrAlertLive;
}Filedist/types/components/GrAlert/grAlertStyles.d.ts
type GrAlertVariant = typeof GR_ALERT_VARIANTS[number];Usage from the library prose
Tone and variant are different axes
tone is responsible for colour and meaning (info, success, warning,
danger, slate, azure), variant for weight: soft (a tinted background) or
outline (a border only). Every combination makes sense.
The colours are expressed entirely in --gr-* tokens, so the message is equally
correct in the light and the dark theme. For pointed adjustments there are the
backgroundColor, textColor and borderColor props, or the --gr-alert-*
variables (see tokens.md).
How the message is announced to a screen reader
The key role here belongs to live, and by default it is derived from the tone:
live | What the element gets | When |
|---|---|---|
auto (the default) | alert for warning/danger, status for the rest | the ordinary case |
assertive | role="alert" — interrupts reading | the message demands an immediate reaction |
polite | role="status" — waits for a pause | the message can be finished later |
off | no role at all | the message has already been announced another way |
The point of the default: role="alert" interrupts speech, and hanging it on
every informational message turns a calm hint into an alarm.
The mode is configurable globally — an application whose alerts must not interrupt speech does not need the prop on every one of them:
<GrConfigProvider :component-defaults="{ GrAlert: { live: 'polite' } }">componentDefaults also sets tone, variant and closable.
The icon
By default the glyph is chosen by the tone. The #icon slot replaces it, the
:icon="false" prop removes it:
<GrAlert tone="success">
<template #icon>
<IconRocket />
</template>
Deploy finished.
</GrAlert>
<GrAlert tone="slate" :icon="false">
Draft saved automatically.
</GrAlert>The icon is decorative in both cases — it stays aria-hidden, because the meaning
is carried by the text, not by the picture. A message without an icon reads more
calmly and belongs where there are many alerts: a dense form, a list of settings.
Actions
“Retry” and “Details” buttons go into the #actions slot rather than into the
text: there they get a place of their own below the message and do not break the
sentence apart.
<GrAlert tone="danger" title="Export failed" closable>
The report service returned 502.
<template #actions>
<GrButton size="sm" tone="danger" @click="retry">Retry</GrButton>
<GrButton size="sm" variant="outline" tone="danger">Open logs</GrButton>
</template>
</GrAlert>Dismissal: close versus v-model:visible
closable adds the button. What happens next is the consumer’s choice:
<!-- the message stays until the screen decides otherwise -->
<GrAlert closable @close="askConfirmation" />
<!-- the message hides itself -->
<GrAlert v-model:visible="shown" closable />visible has no state of its own, and that is deliberate: without the prop the
alert does not disappear on click, it only reports the intent with a close
event. Otherwise the dismiss button would become an irreversible action for
everyone who asks for confirmation on close or writes a mark on the server.
close is emitted in both modes.
Props in this example