PlAlert
A message about something that happened, set into the page it is about. Three shapes (a bare line, a line with a glyph, or a headline with the detail under it) are one component with different slots filled.
import { PlAlert } from 'plass-ui';
<PlAlert color="success">Your changes are live.</PlAlert>;
<PlAlert color="danger" title="The deploy failed">
Two of the health checks never came back.
</PlAlert>;import 'package:plass_ui/plass_ui.dart';
const PlAlert(color: PlassColor.success, child: Text('Your changes are live.'));
const PlAlert(
color: PlassColor.danger,
title: Text('The deploy failed'),
child: Text('Two of the health checks never came back.'),
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variantshared | 'solid' | 'glass' | 'ghost' | 'glass' | What the surface is made of. An alert *is* the thing being coloured, so unlike a container its sheet takes the tint |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The type scale and padding of the glyph, the title and the message |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'info' | The severity. The default is info rather than primary, because an alert is not the primary anything — it is a note |
| densityshared | 'default' | 'compact' | 'default' | Padding only — never the height, never the type scale |
| elevationshared | 0 | 1 | 2 | 3 | 0 | Drop shadow depth. 0 means no shadow at all |
| title | ReactNode | — | The heading line. With it the alert is two-part; without it the whole thing is one line |
| icon | ReactNode | false | — | The glyph at the start. Defaults to the one that goes with color; false drops it, a node replaces it |
| action | ReactNode | — | Content pinned to the end of the row — a Retry button, a link. Kept out of children so it stays on the first line |
| onClose | (event) => void | — | Passing it is what makes the dismiss button appear |
| closeLabel | string | 'Dismiss' | Accessible name of the dismiss button. Never drawn |
| children | ReactNode | — | The message |
| Prop | Type | Default | Description |
|---|---|---|---|
| variantshared | PlassVariant | PlassVariant.glass | What the surface is made of. An alert *is* the thing being coloured, so unlike a container its sheet takes the tint |
| sizeshared | PlassSize | PlassSize.md | The type scale and padding of the glyph, the title and the message |
| colorshared | PlassColor | PlassColor.info | The severity. The default is info rather than primary, because an alert is not the primary anything — it is a note |
| densityshared | PlassDensity | PlassDensity.standard | Padding only — never the height, never the type scale |
| elevationshared | int | 0 | Drop shadow depth. 0 means no shadow at all |
| title | Widget? | — | The heading line. With it the alert is two-part; without it the whole thing is one line |
| icon | Widget? | — | The glyph at the start. Defaults to the one that goes with color; false drops it, a node replaces it |
| showIcon | bool | true | Whether a glyph is drawn at all. React says this with icon={false}; Dart has no value that is neither null nor a widget, so it gets its own name |
| action | Widget? | — | Content pinned to the end of the row — a Retry button, a link. Kept out of children so it stays on the first line |
| onClose | VoidCallback? | — | Passing it is what makes the dismiss button appear |
| closeLabel | String | 'Dismiss' | Accessible name of the dismiss button. Never drawn |
| child | Widget? | — | The message |
Every native <div> attribute passes straight through, role included. See the note on live regions below. color and title are excluded from the pass-through because both are Plass props here.
icon is a Widget? and showIcon is the switch beside it. React says both with one three-way prop, which Dart has no value for. There is null and there is a widget, and nothing that means "take it away".
What the shared axes (variant size color density elevation) mean across the library is in prop conventions.
Examples
variant
An alert is the thing being coloured. A notice about a severity, not a container holding someone else's content, so unlike a PlCard its sheet takes the tint.
solid is the family's gradient with that family's shadow under it and no gloss line, exactly as a filled PlButton has none. glass wears the family in its hairline, its glyph and its title. ghost is the tint alone, for an alert set among form fields where a second bordered rectangle is one rectangle too many.
color
The default is info, not primary. This is the one place primary would be wrong: an alert is a note, and the palette already has the word for that.
Each family draws its own shape as well as its own colour. An alert that says "this went wrong" only in red says it only to some readers.
The three shapes
icon={false}showIcon: false for a bare line, the default for a line with a glyph, and title plus the body for a headline with the detail under it. Nothing about the surface changes between them. Only how much of it is used.action and onClose
action stays on the first line while the message wraps beside it, which is why it is a slot of its own rather than something appended to the body.
Passing onClose is what makes the dismiss button appear. The component does not hide itself. What happens on dismiss is the caller's, because an alert that vanished on its own would have to be told when to come back.
size
Accessibility
- The alert is a live region, and which one depends on the severity:
warninganddangergetrole="alert"and interrupt whatever a screen reader is saying; the rest getrole="status"and wait for a pause. "This failed" is worth interrupting for and "saved" is not. - A
roleyou pass wins, the props spread after the default. - The glyph is decorative and
aria-hidden; the severity is carried by the role, the shape and the colour together, never by the colour alone. - The glyph is centred on the message's first line with
1lh, so a three-line alert still has its glyph at the top. actionand the dismiss button are real buttons with their own tab stops. Give the action an accessible name; the dismiss button has one already.
- The severity decides whether the alert interrupts.
warninganddangerare live regions and are announced as they appear; the rest are read when the reader reaches them. "This failed" is worth interrupting for and "saved" is not. - Flutter has one live region rather than two politeness levels, so what the React build says with
role="alert"againstrole="status"becomes whether the alert is a live region at all. - The glyph is excluded from semantics; the severity is carried by the shape and the colour together, never by the colour alone.
- The glyph is centred on the message's first line (a box the height of one line box, whatever the type scale turns out to be), so a three-line alert still has its glyph at the top.
actionand the dismiss button are real focus stops. Give the action a name; the dismiss button has one already.
Differences from the React build
| React | Flutter | Why |
|---|---|---|
role="alert" / role="status" | a live region, or not one | Flutter has one live-region flag and no politeness levels. The severity still decides; what it decides between is narrower. |
a role you pass wins | — | There is no role to override. A caller who needs different semantics wraps the alert in their own Semantics. |
icon={false} | showIcon: false | Dart has no value that is neither null nor a widget, so "take it away" gets its own name. |
children | child | Flutter's name. |
className, style | — | There is no class list and no style attribute to pass through. |