Skip to main content

Statusbar

Info:Shell html svelte astro Success: coverage 23/23

The footer status strip: a compact, monospace row of status items separated by flexible spacers.

Live demo

live · @xoji/astro

Statusbar

Editor strip — left / center / right via spacers

0 errors Ln 42, Col 7 UTF-8 TypeScript Spaces: 2

Inline glyphs — Badge dots for sync & build

Success:Synced Info:Build passing 0.4.0 100% coverage

Live region — announces changes politely

Deriving theme… 276 tokens OKLCH

Overflow — when content outruns the width

Constrained to a narrow frame so the modes diverge. clip (default) hides the spill, wrap flows onto a second line, scroll adds a horizontal track.

overflow="clip"

main.ts UTF-8 Ln 42, Col 7 Spaces: 2 LF TypeScript Prettier 0 errors

overflow="wrap"

main.ts UTF-8 Ln 42, Col 7 Spaces: 2 LF TypeScript Prettier 0 errors

overflow="scroll"

main.ts UTF-8 Ln 42, Col 7 Spaces: 2 LF TypeScript Prettier 0 errors

Collapse — rank, drop, and tuck into a +N popover

collapse measures the row with a ResizeObserver and drops the lowest data-priority items first, folding them into a +N popover that escapes the bar's clip. Items with data-required never drop. Drag the resize handle to watch it react; click the +N to see what got tucked away. (JS-driven — the row renders un-collapsed until hydrated.)

main.ts 0 errors Prettier LF UTF-8 Spaces: 2 Ln 42, Col 7 TypeScript

Manual overflow — the consumer owns the +N popover

manual-overflow keeps the ranking and dropping but renders no shadow popover: the element fires overflow-change with the dropped cells' actual elements, and the host renders its own popover from them — so styled, interactive cells keep their light-DOM styles and handlers. The blue cells below stay blue (and clickable) when they collapse.

main.ts UTF-8 Ln 42, Col 7 TypeScript

Statusbar is the thin strip that lives along the bottom of an app shell, reporting ambient state: cursor position, encoding, branch, sync status, build result. It is a flex row of item parts you space apart with one or more spacer parts that absorb the slack, so groups push to the left and right edges.

The default treatment is small monospace ink at low contrast; an item--strong modifier lifts a single item to full-contrast foreground for the one fact that matters most. A live flag turns the bar into an aria-live region so screen readers announce status changes as they happen; ideal for build, sync, or save indicators that update in place. Under overflow="collapse" it measures the row with a ResizeObserver, ranks items by data-priority (a data-required item never drops), and folds the lowest-priority ones into a +N popover until the row fits; by default it clones the dropped items into a shadow popover, which is right for plain text/token cells, though a clone can't carry light-DOM styles or event handlers, so set manual-overflow for styled/interactive cells. Whenever the dropped set changes, collapse fires an overflow-change CustomEvent (bubbles, composed, deduped against the last emit) whose detail carries the actual slotted light-DOM cell elements ({ hidden: HTMLElement[]; visible: HTMLElement[] }) so a consumer knows exactly which of its own cells dropped and can render them itself with their original styles and handlers intact.

When to use

How this component composes with the rest of the set.

Sits at the bottom of AppShell as the footer strip, mirroring Toolbar at the top.
Drop a Badge or inline SVG inside an item for sync, branch, or status glyphs.
Use multiple spacer parts to split the bar into left / center / right groups.
For styled or interactive cells, set manual-overflow and listen for overflow-change: the element ranks and hides the dropped cells, your code reads detail.hidden (the originals, styles and handlers intact) and renders them into your own +N popover.

Props

7 props, straight from the manifest.

PropTypeDefaultBindingsDescription
live boolean false
html svelte astro
Marks the bar as a polite live region (`role="status"`, `aria-live="polite"`) so status changes are announced.
label string
html svelte astro
An accessible name for the bar (`aria-label`), useful when the strip is a live region.
overflow "clip" | "wrap" | "scroll" | "collapse"
clip wrap scroll collapse
clip
html svelte astro
How the bar handles content wider than its width. `clip` (default) hides the overflow; `wrap` lets items flow onto multiple lines; `scroll` gives the bar a horizontal scrollbar; `collapse` ranks items and folds the lowest-priority ones into a `+N` popover until the row fits. `collapse` is JS-driven (a `ResizeObserver` measures the fit) and needs the live `html` or `svelte` element; the static `astro` binding has no element to upgrade, so it falls back to `scroll` there to keep every cell reachable.
separated boolean false
html svelte astro
Draws a thin divider between adjacent items at the bar's own spacing, so each cell stays an individual item (and `collapse` counts and drops them independently) instead of carrying its own `Separator`. The leading divider is suppressed at the start of each run — the first item and any item after a `spacer` — and stays correct as items collapse.
data-priority number (per-item attribute) 0
html svelte astro
Set on an individual item (not the bar). Under `overflow="collapse"`, items drop lowest-priority-first when the row can't fit; higher values are kept longer. Ties drop right-to-left so leading items survive. Ignored by every other overflow mode.
data-required boolean (per-item attribute) false
html svelte astro
Set on an individual item. Under `overflow="collapse"`, a required item is never dropped into the `+N` popover regardless of width. Ignored by every other overflow mode.
manual-overflow boolean false
html svelte
Inverts ownership of the overflow contents under `overflow="collapse"`. Off (default), the element renders its own `+N` trigger and a shadow popover, cloning the dropped items into it; this is clean for plain text/token cells, but a clone drops light-DOM (framework-scoped) styles and event handlers, so styled/interactive cells degrade. On, the element still measures, ranks, and hides the lowest-priority cells (`display:none` + a `data-xoji-collapsed` marker) but renders neither the `+N` trigger nor the shadow popover. Instead it fires `overflow-change` so the consumer renders its own light-DOM popover from its original, styled, wired cells. Either way the element fires `overflow-change`; only manual mode suppresses the built-in affordance. Bindings: live on `html`/`svelte`; the static `astro` binding has no element to drive, so the prop is accepted for parity but inert (collapse already falls back to `scroll` there).

Appearance

Variants

item-strong

.xoji-statusbar__item--strong

Lifts a single item to full-contrast foreground and medium weight for emphasis.

States

item-focus-visible

.xoji-statusbar__item:focus-visible

Keyboard focus on an interactive item: a token-colored ring, plus a transparent outline that becomes real in forced-colors mode.

Anatomy

The named parts that make up the component, with their selectors.

statusbar

.xoji-statusbar

The footer strip, a flex row carrying the monospace status items.

--space-4 --space-1 --space-6 --bg-1 --border-thin --line --font-mono --text-xs --fg-2

item

.xoji-statusbar__item

A single status entry: an inline group of label text and any inline graphic.

--space-1

spacer

.xoji-statusbar__spacer

A flexible gap that absorbs free space, pushing items to opposite edges.

--space-2

overflow

.xoji-statusbar__overflow

The +N affordance and its popover, present only under overflow="collapse". The trigger is a compact button; the popover escapes the bar's clip via the top layer and lists the dropped items.

--space-1 --space-2 --space-8 --bg-2 --fg-0 --fg-1 --fg-2 --font-mono --text-xs --border-thin --radius-sm --radius-md --surface-overlay --surface-overlay-border --elevation-3

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 23/23 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--bg-1 --bg-2 --border-normal --border-thick --border-thin --elevation-3 --fg-0 --fg-1 --fg-2 --font-mono --line --radius-md --radius-sm --ring --space-1 --space-2 --space-4 --space-6 --space-8 --surface-overlay --surface-overlay-border --text-xs --weight-medium

Slots

default
html svelte astro

The status items and spacers, in order.

Accessibility

Renders a native <footer> so it is exposed as a content landmark.
live makes the strip a polite aria-live region (role="status") so in-place status updates are announced without stealing focus.
label supplies an aria-label to name the region when its purpose is not obvious from context.
Focusable items receive a token ring and a transparent outline that the forced-colors base rule promotes to a real system outline.
State belongs in the item text, not in color alone; the strong modifier adds weight as well as contrast.

Code

Items, spacers, and a live region

A status row split by a spacer, plus a live-updating build bar.

<xoji-statusbar label="Editor status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong" part="item">main.ts</span>
	<span class="xoji-statusbar__item" part="item">UTF-8</span>
	<span class="xoji-statusbar__item" part="item">Ln 42, Col 8</span>
	<span class="xoji-statusbar__spacer" part="spacer"></span>
	<span class="xoji-statusbar__item" part="item">Spaces: 2</span>
	<span class="xoji-statusbar__item" part="item">TypeScript</span>
</xoji-statusbar>

<xoji-statusbar live label="Build status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong" part="item">Build passing</span>
	<span class="xoji-statusbar__spacer" part="spacer"></span>
	<span class="xoji-statusbar__item" part="item">12.4s</span>
</xoji-statusbar>
<script lang="ts">
	import { Statusbar } from "@xoji/svelte";
</script>

<Statusbar label="Editor status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong">main.ts</span>
	<span class="xoji-statusbar__item">UTF-8</span>
	<span class="xoji-statusbar__item">Ln 42, Col 8</span>
	<span class="xoji-statusbar__spacer"></span>
	<span class="xoji-statusbar__item">Spaces: 2</span>
	<span class="xoji-statusbar__item">TypeScript</span>
</Statusbar>

<Statusbar live label="Build status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong">Build passing</span>
	<span class="xoji-statusbar__spacer"></span>
	<span class="xoji-statusbar__item">12.4s</span>
</Statusbar>
---
import { Statusbar } from "@xoji/astro";
---

<Statusbar label="Editor status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong">main.ts</span>
	<span class="xoji-statusbar__item">UTF-8</span>
	<span class="xoji-statusbar__item">Ln 42, Col 8</span>
	<span class="xoji-statusbar__spacer"></span>
	<span class="xoji-statusbar__item">Spaces: 2</span>
	<span class="xoji-statusbar__item">TypeScript</span>
</Statusbar>

<Statusbar live label="Build status">
	<span class="xoji-statusbar__item xoji-statusbar__item--strong">Build passing</span>
	<span class="xoji-statusbar__spacer"></span>
	<span class="xoji-statusbar__item">12.4s</span>
</Statusbar>