Status Bar

Singleton floating area for short, non-critical, transient feedback.

  • A status bar is a single live region, not a stacked toaster. New messages replace the previous one.
  • Keep one element in the HTML, empty by default. JavaScript only updates its text content; it shows when non-empty and hides when empty, while staying available as a live region.
  • Use it for transient status (Saved., Reconnected., Copied.). Critical, persistent, or actionable information belongs in .alert, inline messages, or dialogs.
  • Intents: danger, success, warning, neutral. The default (no intent) is a neutral dark pill.
<form class="needs-validation" data-validation-message="Please check the highlighted fields.">
  <label class="field">
    <span class="field-label">Email</span>
    <input class="input" type="email" name="email" required
           aria-describedby="sb-email-error" />
    <span class="field-error" id="sb-email-error" role="alert">Enter a valid email.</span>
  </label>
  <div class="form-actions">
    <button class="btn primary" type="submit">Submit</button>
  </div>
</form>

Submitting the empty form blocks submission and shows data-validation-message in the status bar below — no JavaScript required beyond the runtime.

<div class="cluster">
  <button class="btn" type="button" commandfor="sb-status" command="--status"
          aria-controls="sb-status"
          data-status-message="Saved." data-status-intent="success">Show success</button>
  <button class="btn" type="button" commandfor="sb-status" command="--status"
          aria-controls="sb-status"
          data-status-message="Could not save." data-status-intent="danger"
          data-status-duration="6000">Show danger</button>
  <button class="btn outline" type="button" commandfor="sb-status" command="--status-clear"
          aria-controls="sb-status">Clear</button>
</div>

<div class="status-bar" data-status id="sb-status" role="status" aria-live="polite" aria-atomic="true"></div>

No script required beyond the runtime: command="--status" reads its message from data-status-message (plus optional data-status-intent / data-status-duration), command="--status-clear" empties the bar. commandfor must match the status bar's own id. For dynamic messages — a fetch response, a computed value — dispatch the same event the commands use under the hood:

document.dispatchEvent(new CustomEvent("actual:status", {
  bubbles: true,
  detail: { message: "Saved.", intent: "success" },
}));

The runtime auto-wires the status bar to Actual's form validation: a form that fails to submit shows its data-validation-message in the status bar with the danger intent. No target in the DOM means the call is a no-op, so the markup stays optional.