oriUI

Alert

A styled, accessible notification banner. Its live-region politeness is derived from the color — urgent danger / warn render role="alert" (assertive), everything else role="status" (polite) — so a non-urgent banner isn't announced assertively (override with the live prop). It supports an optional icon, a title, body text, an actions row, and a dismiss button.

The examples are organised by layer: the class reference is the standalone @oriui/css layer, and the Framework API is the @oriui/vue component. Every example is live — flip its code between HTML (the standalone classes, also your htmx / Astro / Svelte / plain-HTML usage), Vue; HTML is the default.

Classes

An alert is a block class plus single-class token utilities — one class repoints one token; no base class needed. The Vue props in Framework API map 1:1 to these.

ClassTypeDescription
ori-alertBlockRequired base class. The Vue component sets role=alert (danger/warn) or role=status (otherwise); standalone markup picks the role itself.
ori-variant_*Stylefill · tonal · outline · text · plain
ori-color_*Colorprimary · secondary · success · warn · danger · info · surface · background
ori-size-radius_*Radiuszero · xs · sm · md · lg · xl · rounded
ori-font-size_*Sizexs · sm · md · lg · xl · xxl — scales the body text
ori-alert__icon · ori-alert__content · ori-alert__title · ori-alert__body · ori-alert__actions · ori-alert__closePartinternal layout elements

Like Button, the non-fill variants (the default tonal included) paint the body text with the AA-safe --ori-color-text tone rather than the raw role — see Design tokens.

Variants

Five visual styles, all driven by the ori-variant_* utility. tonal is the default.

Fill alert
Tonal alert
Outline alert
Text alert
Plain alert
html
<div class="ori-alert ori-variant_tonal ori-color_info" role="status">
    <div class="ori-alert__content">
        <div class="ori-alert__body">Tonal alert</div>
    </div>
</div>
<!-- swap the variant: ori-variant_tonal → ori-variant_fill / ori-variant_outline / ori-variant_text / ori-variant_plain -->
vue
<OriAlert text="Fill alert" variant="fill" color="info" />
<OriAlert text="Tonal alert" variant="tonal" color="info" />
<OriAlert text="Outline alert" variant="outline" color="info" />
<OriAlert text="Text alert" variant="text" color="info" />
<OriAlert text="Plain alert" variant="plain" color="info" />

Colors

Every semantic role. Use success, warn, danger, and info for status messages.

Primary
Secondary
Success
Info
html
<!-- swap the color: ori-color_info → ori-color_success / ori-color_warn / ori-color_danger / ori-color_primary -->
<div class="ori-alert ori-variant_tonal ori-color_danger" role="alert">
    <div class="ori-alert__content">
        <div class="ori-alert__body">Danger</div>
    </div>
</div>
vue
<OriAlert text="Primary" color="primary" />
<OriAlert text="Success" color="success" />
<OriAlert text="Warning" color="warn" />
<OriAlert text="Danger" color="danger" />
<OriAlert text="Info" color="info" />

Variant and color compose freely — e.g. an outline danger alert:

Your changes have been saved.
html
<div class="ori-alert ori-variant_outline ori-color_danger" role="alert">
    <div class="ori-alert__content">
        <div class="ori-alert__body">Something went wrong. Please try again.</div>
    </div>
</div>
vue
<OriAlert text="Something went wrong. Please try again." variant="outline" color="danger" />
<OriAlert text="Your changes have been saved." variant="fill" color="success" />

With title

Pass title to add a bold heading above the body text.

html
<div class="ori-alert ori-variant_tonal ori-color_warn" role="alert">
    <div class="ori-alert__content">
        <div class="ori-alert__title">Session expired</div>
        <div class="ori-alert__body">Please sign in again to continue.</div>
    </div>
</div>
vue
<OriAlert title="Session expired" text="Please sign in again to continue." color="warn" />

With icon

Pass an SVG path to icon to prepend a visual cue.

Success
Your profile has been updated.
html
<div class="ori-alert ori-variant_tonal ori-color_success" role="status">
    <div class="ori-alert__icon">
        <i class="ori-icon" aria-hidden="true">
            <svg viewBox="0 0 24 24"><path d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" /></svg>
        </i>
    </div>
    <div class="ori-alert__content">
        <div class="ori-alert__title">Success</div>
        <div class="ori-alert__body">Your profile has been updated.</div>
    </div>
</div>
vue
<!-- success -->
<OriAlert
    title="Success"
    text="Your profile has been updated."
    color="success"
    icon="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
/>
<!-- warning -->
<OriAlert
    title="Warning"
    text="Disk space is running low."
    color="warn"
    icon="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"
/>

Dismissible

closable adds a close button in the top-right corner. Handle the close event to remove or hide the alert. The button label defaults to "Dismiss" and is configurable via closeLabel.

Update available
A new version is ready to install.
html
<div class="ori-alert ori-variant_tonal ori-color_info" role="status">
    <div class="ori-alert__content">
        <div class="ori-alert__title">Update available</div>
        <div class="ori-alert__body">A new version is ready to install.</div>
    </div>
    <button type="button" class="ori-alert__close" aria-label="Dismiss">
        <!-- close icon -->
    </button>
</div>
vue
<script setup lang="ts">
import { ref } from 'vue';
const visible = ref(true);
</script>

<template>
    <OriAlert
        v-if="visible"
        title="Update available"
        text="A new version is ready to install."
        color="info"
        closable
        @close="visible = false"
    />
</template>

Sizes

size scales the body text from xs to xxl. The default is md.

Extra small alert
Small alert
Medium alert (default)
Large alert
html
<!-- swap the font-size: ori-font-size_md → ori-font-size_xs / ori-font-size_sm / ori-font-size_lg / ori-font-size_xl / ori-font-size_xxl -->
<div class="ori-alert ori-font-size_lg ori-variant_tonal ori-color_info" role="status">
    <div class="ori-alert__content">
        <div class="ori-alert__body">Large alert</div>
    </div>
</div>
vue
<OriAlert text="Extra small alert" size="xs" color="info" />
<OriAlert text="Small alert" size="sm" color="info" />
<OriAlert text="Medium alert (default)" size="md" color="info" />
<OriAlert text="Large alert" size="lg" color="info" />

Radius

From zero (sharp corners) to rounded (pill). Default is md.

No radius
Small radius
Medium radius (default)
Large radius
Rounded
html
<!-- swap the radius: ori-size-radius_md → ori-size-radius_zero / ori-size-radius_sm / ori-size-radius_lg / ori-size-radius_xl / ori-size-radius_rounded -->
<div class="ori-alert ori-size-radius_rounded ori-variant_tonal ori-color_info" role="status">
    <div class="ori-alert__content">
        <div class="ori-alert__body">Rounded</div>
    </div>
</div>
vue
<OriAlert text="No radius" radius="zero" color="info" />
<OriAlert text="Medium radius (default)" radius="md" color="info" />
<OriAlert text="Rounded" radius="rounded" color="info" />

Common patterns

A form submission result and a persistent banner with actions — the everyday compositions.

html
<!-- form error banner -->
<div class="ori-alert ori-variant_outline ori-color_danger" role="alert">
    <div class="ori-alert__icon">
        <i class="ori-icon" aria-hidden="true">
            <svg viewBox="0 0 24 24">
                <path
                    d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"
                />
            </svg>
        </i>
    </div>
    <div class="ori-alert__content">
        <div class="ori-alert__title">Payment failed</div>
        <div class="ori-alert__body">Your card was declined. Check your details and try again.</div>
    </div>
    <button type="button" class="ori-alert__close" aria-label="Dismiss"><!-- icon --></button>
</div>

<!-- alert with actions row -->
<div class="ori-alert ori-variant_tonal ori-color_warn" role="alert">
    <div class="ori-alert__content">
        <div class="ori-alert__title">New terms of service</div>
        <div class="ori-alert__body">We have updated our terms. Please review before continuing.</div>
        <div class="ori-alert__actions">
            <button class="ori-button ori-variant_tonal ori-color_warn …">Review</button>
            <button class="ori-button ori-variant_text ori-color_warn …">Dismiss</button>
        </div>
    </div>
</div>
vue
<!-- form error banner -->
<OriAlert
    title="Payment failed"
    text="Your card was declined. Check your details and try again."
    color="danger"
    variant="outline"
    icon="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"
    closable
    @close="handleDismiss"
/>

<!-- alert with an actions slot -->
<OriAlert
    title="New terms of service"
    text="We have updated our terms. Please review before continuing."
    color="warn"
    variant="tonal"
>
    <template #actions>
        <OriButton text="Review" size="sm" variant="tonal" color="warn" />
        <OriButton text="Dismiss" size="sm" variant="text" color="warn" />
    </template>
</OriAlert>

Accessibility

The accessibility contract holds across every layer — the standalone classes and the Vue component render the same attributes.

  • The live-region politeness is derived from the color so non-urgent content isn't announced assertively: urgent colors (danger / warn) render role="alert" (aria-live="assertive" — interrupts the screen reader), and everything else (the info default, success, …) renders role="status" (aria-live="polite" — announced at the next pause). Override with the live prop (assertive / polite / off); off removes the live region entirely (for content that is part of the static page and shouldn't be announced as it appears).
  • Icons inside the alert are decorative (aria-hidden="true" on the ori-icon); the alert text itself is the accessible announcement.
  • The dismiss button has an aria-label (default "Dismiss", configurable via closeLabel) so its purpose is clear without visible text.
  • The dismiss button has a visible :focus-visible ring. No other keyboard interaction is required; the alert itself is not focusable.
  • For a live announcement, insert (or reveal) the element with its content already in place — some screen readers announce only content present when the region appears. For content that is part of the page on load, prefer live="off" (or a non-urgent color) so it isn't announced as the page renders.
KeyAction
TabMoves focus to the dismiss button (if present).
EnterActivates the focused dismiss button.
SpaceActivates the focused dismiss button.

Framework API

The props, events, slots, and slots of the Vue component. The standalone CSS layer has no component API — its surface is the classes above. (Svelte bindings are planned.)

Props

PropTypeDefaultDescription
closablebooleanfalseRenders a dismiss button; emit close to remove the alert.
closeLabelstring'Dismiss'aria-label on the dismiss button.
colorThemeColor'info'Semantic role: primary · secondary · success · warn · danger · info · surface · background.
iconstringSVG path for the leading icon. Use the icon slot for custom markup.
live'assertive' | 'polite' | 'off'derivedLive-region politeness. Defaults to assertive (role="alert") for danger / warn and polite (role="status") otherwise; off removes the live region.
radiusRadiusSize'md'Corner radius (zero · xs · sm · md · lg · xl · rounded).
sizeActionSize'md'Body font scale (xsxxl).
textstringBody text. Use the default slot for richer markup.
titlestringBold heading above the body. Use the title slot for richer markup.
variant'fill' | 'tonal' | 'outline' | 'text' | 'plain''tonal'Visual style.

ThemeColor: 'primary' | 'secondary' | 'success' | 'warn' | 'danger' | 'info' | 'surface' | 'background'

ActionSize: 'text' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'

RadiusSize: 'zero' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'rounded'

Events & attributes

EventPayloadDescription
closeEmitted when the dismiss button is clicked. Use it to hide or remove the alert.

OriAlert does not set inheritAttrs: false, so extra attributes (class, style, data-*, …) fall through to the root <div> (whose role is alert / status / none per the live rule above).

Slots

SlotDescription
defaultBody content. Replaces the text prop; renders inside ori-alert__body.
iconCustom icon markup. Replaces the icon prop; renders inside ori-alert__icon.
titleCustom title markup. Replaces the title prop; renders inside ori-alert__title.
actionsAction controls (buttons, links) rendered in a flex row below the body (ori-alert__actions). Only mounted when the slot is provided.