Alerts
tier 2 — classesAn inline banner that explains a state, in place, on the page. Four variants, same semantic families as the buttons and badges.
0.2.0.
Variants
Always pair the colour with an icon — colour alone is not an accessible signal.
<div class="alert alert-info">
<i class="ri-information-line"></i>
<span>You are in <strong>demo mode</strong>. Nothing you do here reaches a real system.</span>
</div>
<div class="alert alert-go">
<i class="ri-check-line"></i>
<span>All 128 orders are up to date. Last sync 30 seconds ago.</span>
</div>
<div class="alert alert-warn">
<i class="ri-alert-line"></i>
<span>The workflow API is unreachable. The queue is showing the last known state.</span>
</div>
<div class="alert alert-danger">
<i class="ri-error-warning-line"></i>
<span>Writes are failing. Your last decision was <strong>not</strong> saved — retry it.</span>
</div>
With an action
.alert is a flex row, so margin-left:auto on a trailing button
pushes it to the end.
<div class="alert alert-warn">
<i class="ri-alert-line"></i>
<span>Your session expires in 2 minutes.</span>
<button class="btn btn-sm" style="margin-left:auto">Stay signed in</button>
</div>
Read-only mode
The pattern for telling a viewer-role user why every control is disabled.
Reservation: reroute to EU-West (confidence 0.87).
<div>
<div class="alert alert-info">
<i class="ri-eye-line"></i>
<span>Read-only access. You can see everything here, but not decide anything.</span>
</div>
<div class="card">
<div class="card-head">
<strong>ORD-4209</strong>
<span class="badge badge-warn">Pending</span>
</div>
<div class="card-body">
<p class="form-hint">Reservation: reroute to EU-West (confidence 0.87).</p>
</div>
<div class="modal-footer">
<button class="btn" disabled>Reject</button>
<button class="btn btn-go" disabled><i class="ri-check-line"></i> Approve & send</button>
</div>
</div>
</div>
A validation summary
One alert at the top of the form saying nothing was saved, with a link to each field that needs attention — so a keyboard or screen-reader user reaches the first problem in one keystroke instead of tabbing the whole form to find it.
The summary does not replace the per-field messages. Each control keeps
aria-invalid and an aria-describedby pointing at its own
.form-error, because that is what is read when focus arrives.
<form style="max-width:520px">
<div class="alert alert-danger">
<i class="ri-error-warning-line"></i>
<span>
<strong>Nothing was saved.</strong> Two fields need attention:
<a href="#vs-email">a work e-mail address</a> and
<a href="#vs-region">a region</a>.
</span>
</div>
<div class="form-field">
<label class="form-label form-label--required" for="vs-email">Work e-mail</label>
<input class="form-input" id="vs-email" type="email" value="alex.fischer"
aria-invalid="true" aria-describedby="vs-email-error" />
<p class="form-error" id="vs-email-error">
<i class="ri-error-warning-line"></i> This is not a complete address.
</p>
</div>
<div class="form-field">
<label class="form-label form-label--required" for="vs-region">Region</label>
<select class="form-input form-select" id="vs-region" aria-invalid="true"
aria-describedby="vs-region-error">
<option value="" selected>Choose a region…</option>
<option>EU-West</option>
<option>EU-Central</option>
</select>
<p class="form-error" id="vs-region-error">
<i class="ri-error-warning-line"></i> Orders cannot be routed without one.
</p>
</div>
<div class="form-actions">
<button class="btn" type="button">Cancel</button>
<button class="btn btn-primary" type="button">Save</button>
</div>
</form>