Skip to content
ShineUI
Install

Message

Inline notices that stay put.

<sui-message>FeedbackStable

About

Inline notice bound to a place on the page: a closed period, an overdue balance, a failed bank connection. Five severities each have a tint and an edge. Use it for news that should stay put, and sui-toast-host for news that can fade. The dismiss control sets the native hidden attribute; remove it to show the band again.

Usage

<sui-message severity="info" heading="July is closed" closable> Entries before Aug 1 are locked. </sui-message> <script type="module"> import { defineCustomElements } from "@shineui/core/loader"; import "@shineui/core/shineui.css"; defineCustomElements(); const el = document.querySelector("sui-message"); el.addEventListener("suiClose", (e) => console.log(e.detail)); </script>
import { SuiMessage } from "@shineui/react"; import "@shineui/core/shineui.css"; export function Example() { return ( <SuiMessage severity="info" heading="July is closed" closable onSuiClose={(e) => console.log(e.detail)}> Entries before Aug 1 are locked. </SuiMessage> ); }
<script setup> import { SuiMessage } from "@shineui/vue"; import "@shineui/core/shineui.css"; const onChange = (e) => console.log(e.detail); </script> <template> <SuiMessage severity="info" heading="July is closed" closable @sui-close="onChange">Entries before Aug 1 are locked.</SuiMessage> </template>
import { Component } from "@angular/core"; import { SuiMessage } from "@shineui/angular"; @Component({ standalone: true, imports: [SuiMessage], template: `<sui-message severity="info" heading="July is closed" closable (suiClose)="onChange($event)">Entries before Aug 1 are locked.</sui-message>`, }) export class Example { onChange(e: CustomEvent) { console.log(e.detail); } }

Basic

A heading, a body and the dismiss control. The band renders role="status" and announces itself on insertion, so render one only when it is news.

Entries before Aug 1 are locked.
<sui-message severity="info" heading="July is closed" closable>Entries before Aug 1 are locked.</sui-message>

Severities

Every severity draws one frame: its tint, a 1px edge in its own color, the icon in its ink and the heading in the body ink. Critical adds a 4px rule on its start edge and renders role="alert", which interrupts a screen reader; the rest are role="status" and wait their turn.

Entries before Aug 1 are locked. PMT-0921 applied to INV-1043. ReviewRiverbend Dental Group and Kye's Catering owe $20,220.00. Reconnect First Harrison 4402 to keep the feed current. Tip: press N anywhere to start a new invoice.
<div style="display:flex;flex-direction:column;gap:12px;"> <sui-message severity="info" heading="July is closed">Entries before Aug 1 are locked.</sui-message> <sui-message severity="positive" heading="Payment recorded">PMT-0921 applied to INV-1043.</sui-message> <sui-message severity="attention" heading="2 invoices are overdue"><a slot="action" href="#">Review</a>Riverbend Dental Group and Kye's Catering owe $20,220.00.</sui-message> <sui-message severity="critical" heading="Bank connection expired">Reconnect First Harrison 4402 to keep the feed current.</sui-message> <sui-message severity="neutral">Tip: press <b>N</b> anywhere to start a new invoice.</sui-message> </div>

Heading and body

A heading on its own, a body on its own, and both together. The heading takes its lower margin only when there is a body under it.

Draft saved to Operating Checking. JE-0331 is in the July ledger.
<div style="display:flex;flex-direction:column;gap:12px;"> <sui-message severity="info" heading="Entry posted"></sui-message> <sui-message severity="info">Draft saved to Operating Checking.</sui-message> <sui-message severity="info" heading="Entry posted">JE-0331 is in the July ledger.</sui-message> </div>

Action and icon

The action slot sits after the body and takes a link or a small button. Set icon to any Font Awesome class to replace the severity icon.

ReviewRiverbend Dental Group and Kye's Catering owe $20,220.00. OpenOperating Checking 4402 has 14 unmatched lines.
<div style="display:flex;flex-direction:column;gap:12px;"> <sui-message severity="attention" heading="2 invoices are overdue"><a slot="action" href="#">Review</a>Riverbend Dental Group and Kye's Catering owe $20,220.00.</sui-message> <sui-message severity="attention" icon="fa-regular fa-clock" heading="Reconciliation is due Friday"><a slot="action" href="#">Open</a>Operating Checking 4402 has 14 unmatched lines.</sui-message> </div>

Closable and events

The X is the small icon button sui-dialog and sui-drawer also use, named "Dismiss". Tab reaches it and Enter or Space presses it. suiClose fires first with detail "close-button"; unless a listener calls preventDefault(), as the second band does, the band takes the native hidden attribute; remove it to show the band.

Press the X. The band closes itself. Press the X. A listener vetoes the close.
Idle.
<div style="display:flex;flex-direction:column;gap:12px;"> <sui-message id="msg-plain" severity="info" heading="July is closed" closable>Press the X. The band closes itself.</sui-message> <sui-message id="msg-veto" severity="critical" heading="Bank connection expired" closable>Press the X. A listener vetoes the close.</sui-message> <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;"> <sui-button id="msg-reset" variant="outline" label="Show both again"></sui-button> <span id="msg-log" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted);">Idle.</span> </div> </div>
// setup(root): properties and events setup(root) { const log = root.querySelector('#msg-log'); const plain = root.querySelector('#msg-plain'); const veto = root.querySelector('#msg-veto'); plain.addEventListener('suiClose', (e) => { log.textContent = `suiClose "${e.detail}". Nothing vetoed it, so the band is hidden.`; }); veto.addEventListener('suiClose', (e) => { e.preventDefault(); log.textContent = `suiClose "${e.detail}" vetoed with preventDefault(). The band is still shown.`; }); root.querySelector('#msg-reset').addEventListener('click', () => { plain.hidden = false; veto.hidden = false; log.textContent = 'hidden removed from both bands.'; }); }

Keyboard

KeyAction
TabLands on the dismiss control when closable is set, and on any control in the action slot. The message itself is a live region and takes no focus.
Enter SpaceOn the dismiss control, emits a cancelable suiClose with reason close-button and hides the message unless a listener cancels it.

API

<sui-message>

Properties

PropertyAttributeTypeDefaultDescription
closableclosablebooleanfalseShows the dismiss control: the small sui-icon-button labeled "Dismiss" that sui-dialog, sui-drawer and sui-toast-host also use, so every close control in the library is one part. Dismissing puts the native hidden attribute on the host, which takes the band off the page and out of the accessibility tree; remove hidden (or set el.hidden = false) to show it again.
headingheadingstringstring | undefinedBold first line. Named heading because title is the native tooltip attribute.
iconiconstringstring | undefinedFont Awesome class overriding the severity icon, e.g. "fa-regular fa-clock".
severityseveritySuiSeverity"attention" | "critical" | "info" | "neutral" | "positive"'info'Severity from the shared ladder. Every severity draws one frame: its tint, a 1px edge in its own mark color, the icon in its ink and the heading in the body ink. info is the brand's, positive the brand's in brand mode and green in semantic, attention the accent's, neutral a quiet outline, and critical the danger tint with a 4px rule on its start edge, which is what tells it from attention when the two share a hue in brand mode. critical renders role="alert" and interrupts; the others are role="status". Every icon is aria-hidden, so the heading and body carry the whole message.

Events

EventDetailReactVueDescription
suiCloseSuiCloseReason"cancel" | "close-button" | "escape" | "outside" | "pick" | "scrim" | "trigger"onSuiClose@sui-closeFires before the dismiss control hides the message; detail is 'close-button'. Cancelable: preventDefault() keeps it shown (confirm first, then set hidden yourself). It does not bubble, as no suiClose in the library does.

Slots

SlotDescription
(default)Message body text.
actionOptional inline action (a link or small button) rendered after the body.

Types

SuiCloseReason typeWhy a dismissible surface is closing. Detail of the cancelable suiClose. A consumer expresses "a stray backdrop click must not close this" by calling preventDefault() on the reason it does not accept, which is why none of these needs a prop of its own.
No members.
SuiSeverity type
No members.

Theming

Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.

See also