Light surface
Quiet borders and clear text.
VOXBIT UI · WORK IN PROGRESS
The same foundations and components that power the playground. Adjust a token, inspect the states, and bring the pattern into another interface.
Edit src/ui/tokens.css for system-wide changes. Components use semantic colors, a shared type scale, spacing, radii, focus and motion tokens. Canvas artwork has its own palettes.
Give sound a little soul.
Section title · 18px
Body · 16px / 1.6 — clear language and comfortable reading.
Control label · 14px
Supporting text · 12px
| Token | Current value |
|---|
Include the CSS entry point, apply the root class, then copy a component below. Keep native labels and ARIA attributes; give repeated instances unique IDs. Interactive recipes include their JavaScript. Gallery layout classes are only for arranging examples.
<link rel="stylesheet" href="./src/ui/ui.css">
<body class="vb-root">
<button class="vb-button vb-button--primary">Continue</button>
</body>
For another project, copy src/ui/{ui,tokens,components,icons}.css, the font referenced by tokens.css and its license, and THIRD_PARTY_NOTICES.md. Adjust the font URL for your folders. Behavior helpers are optional. This is an internal library; there is no published package yet.
Use one primary action per task. Ghost buttons support lower-emphasis actions. Disabled buttons cannot activate; busy actions retain a descriptive label.
<div class="gallery-row">
<button class="vb-button vb-button--primary">Primary action</button>
<button class="vb-button vb-button--secondary">Secondary action</button>
<button class="vb-button vb-button--ghost">Quiet action</button>
<button class="vb-button vb-button--primary" disabled>Unavailable</button>
<button class="vb-button vb-button--secondary" aria-busy="true" disabled>Preparing…</button>
</div>
Use an accessible name for every icon-only action. Decorative icons inherit text color; keep their meaning consistent across pages.
<div class="gallery-row">
<button class="vb-button vb-icon-button vb-icon-reset" aria-label="Reset example" title="Reset example"></button>
<button class="vb-button vb-icon-button vb-icon-expand" aria-label="Expand example" title="Expand example"></button>
<button class="vb-button vb-button--primary vb-button--icon vb-icon-microphone">Enable microphone</button>
<a class="vb-link vb-link--icon vb-icon-external" href="./">Open playground</a>
</div>
Motion: 200ms ease-out. Selection changes immediately; the background follows. Try switching quickly or resizing the page. Initial position and layout corrections do not animate.
A named group of mutually exclusive toggle buttons. Tab visits each option; Space or Enter selects it. The consumer owns the selection and updates aria-pressed.
Comfortable selected.
<div class="vb-segmented" role="group" aria-label="Example density" data-demo-segment>
<button aria-pressed="true">Comfortable</button>
<button aria-pressed="false">Compact</button>
<button aria-pressed="false" disabled>Unavailable</button>
</div>
<p class="vb-hint" data-selection role="status">Comfortable selected.</p>
<script type="module">
import { bindSegmentedMotion } from './src/ui/controls.js';
const group = document.querySelector('[data-demo-segment]');
const motion = bindSegmentedMotion(group);
// Before removing the control: motion.destroy();
group.onclick = event => {
const button = event.target.closest('button');
if (!button || button.disabled) return;
for (const item of group.children) item.setAttribute('aria-pressed', String(item === button));
document.querySelector('[data-selection]').textContent = `${button.textContent} selected.`;
};
</script>
Associate a label and output with the native range. Arrow keys adjust by one step. bindRange supplies the readout; your application supplies the meaning.
Adjust with the slider or arrow keys.
<label class="vb-field-label" for="example-motion">Motion <output aria-hidden="true" id="example-motion-value" for="example-motion">40%</output></label>
<input class="vb-range" id="example-motion" type="range" min="0" max="100" value="40" aria-describedby="example-motion-hint">
<p class="vb-hint" id="example-motion-hint">Adjust with the slider or arrow keys.</p>
<script type="module">
import { bindRange } from './src/ui/controls.js';
const range = bindRange(document.querySelector('#example-motion'),
document.querySelector('#example-motion-value'), {
format: value => `${value}%`,
onInput: value => { /* Apply the value to your feature here. */ },
});
// After programmatic value changes: range.sync();
// Before removing the controls: range.destroy();
</script>
Keep a visible label and value beside the native picker. The native picker provides platform keyboard interaction.
<div class="vb-field-row">
<label for="example-color">Accent color</label>
<div class="vb-color-value"><input class="vb-color" type="color" id="example-color" value="#687f4e"><output aria-hidden="true" id="example-color-value" for="example-color">#687F4E</output></div>
</div>
<script type="module">
document.querySelector('#example-color').oninput = event => {
document.querySelector('#example-color-value').textContent = event.target.value.toUpperCase();
};
</script>
Motion: 140ms ease-out. The thumb travels with the track color. Reduced motion makes both changes immediate.
Use a native checkbox with a visible label. Space toggles the setting; checked is the single source of truth.
<label class="vb-field-row" for="example-glow">Soft glow <input class="vb-switch" role="switch" id="example-glow" type="checkbox" checked></label>
<label class="vb-field-row" for="example-unavailable">Unavailable setting <input class="vb-switch" role="switch" id="example-unavailable" type="checkbox" disabled></label>
The popup uses Voxbit styling where customizable native selects are supported. Other browsers retain their platform picker.
Use a native select for longer choice lists. An invalid field must explain how to recover, using aria-describedby and visible text.
Choose a source to continue.
<label class="vb-field-label vb-field-label--stack" for="example-source">Audio source</label>
<select class="vb-select" id="example-source" aria-invalid="true" aria-describedby="example-source-error">
<option value="">Choose a source</option><option value="microphone">Microphone</option><option value="file">Audio file</option>
</select>
<p class="vb-error" id="example-source-error" role="status">Choose a source to continue.</p>
<script type="module">
document.querySelector('#example-source').onchange = event => {
const invalid = !event.target.value;
event.target.setAttribute('aria-invalid', String(invalid));
document.querySelector('#example-source-error').textContent = invalid ? 'Choose a source to continue.' : '';
};
</script>
Use details and summary for progressive settings. Enter or Space toggles the section. The browser owns open state; CSS mirrors it in the chevron.
Place specialized controls here. Keep common adjustments visible.
<details class="vb-disclosure">
<summary>Fine tune <span class="vb-icon vb-icon-chevron" aria-hidden="true"></span></summary>
<p class="vb-hint">Place specialized controls here. Keep common adjustments visible.</p>
</details>
Cards are surfaces, not automatically interactive. Use headings for structure and explicit links or buttons for actions. Theme tokens can be scoped to a subtree.
Quiet borders and clear text.
The same component, new tokens.
<div class="gallery-theme-pair">
<div data-theme="light" class="gallery-theme"><article class="vb-card"><h3>Light surface</h3><p class="vb-hint">Quiet borders and clear text.</p><button class="vb-button vb-button--primary">Primary action</button></article></div>
<div data-theme="dark" class="gallery-theme"><article class="vb-card"><h3>Dark surface</h3><p class="vb-hint">The same component, new tokens.</p><button class="vb-button vb-button--primary">Primary action</button></article></div>
</div>
Use showModal() for a modal with native focus containment. Escape closes it; focus returns to the trigger. Associate the dialog with its heading.
<button class="vb-button vb-button--secondary" data-open-dialog>Open example dialog</button>
<dialog class="vb-dialog" id="example-dialog" aria-labelledby="example-dialog-title">
<h2 id="example-dialog-title">Your settings</h2>
<p>This is a UI example. No audio is accessed or uploaded.</p>
<form method="dialog"><button class="vb-button vb-button--primary">Done</button></form>
</dialog>
<script type="module">
document.querySelector('[data-open-dialog]').onclick = () => {
document.querySelector('#example-dialog').showModal();
};
</script>
Keep the native input keyboard-accessible inside its visible label. This gallery reports a filename only; it does not read or upload its contents.
No file selected.
<label class="vb-button vb-button--ghost vb-button--icon vb-icon-upload vb-file">Choose audio
<input type="file" accept="audio/*" id="example-file">
</label>
<p class="vb-hint" id="example-file-status" role="status">No file selected.</p>
<script type="module">
document.querySelector('#example-file').onchange = event => {
document.querySelector('#example-file-status').textContent = event.target.files[0]?.name || 'No file selected.';
};
</script>
Behavior notes: buttons in the visual specimens are inert. The segmented control, range, color, checkbox, select, disclosure, dialog, file input, theme switch and copy actions are interactive. Use Tab to inspect focus states. Native browser behavior remains part of the component contract.