High-level, declarative web components built on top of the Orbit CSS framework.
Orbit gives you primitives — a CSS engine for radial layout. It's powerful,
but composing a single widget means nesting five levels
(.bigbang > .gravity-spot > .orbit-N > .satellite > .capsule) and getting the
rules exactly right. That depth is the main barrier to entry, for humans and
for LLMs.
orbit-kit wraps the common radial patterns into one-line custom elements — gauges, charts, activity rings, knobs, pie menus, cockpit instruments, analog clocks, compasses and radars:
<!-- Before: raw primitives -->
<div class="bigbang" style="width:200px;aspect-ratio:1">
<div class="gravity-spot">
<div class="orbit-4" style="--o-range:270deg;--o-from:225deg">
<o-progress value="72" shape="rounded"
style="--o-fill:#6366f1;--o-stroke-width:8"></o-progress>
</div>
<div class="orbit-0">
<div class="satellite at-center"><div class="capsule">72%</div></div>
</div>
</div>
</div>
<!-- After: orbit-kit -->
<o-gauge value="72" unit="%"></o-gauge>npm install @zumer/orbit @zumer/orbit-kitimport '@zumer/orbit/style' // Orbit CSS engine
import '@zumer/orbit' // Orbit core web components (<o-arc>, <o-progress>)
import '@zumer/orbit-kit' // registers every kit componentOr straight from a CDN — no build step:
<link rel="stylesheet" href="https://unpkg.com/@zumer/orbit@latest/dist/orbit.css">
<script src="https://unpkg.com/@zumer/orbit@latest/dist/orbit.js"></script>
<script type="module" src="https://unpkg.com/@zumer/orbit-kit@latest/src/orbit-kit.js"></script>@zumer/orbit is a peer dependency — the kit assumes the Orbit core (CSS +
<o-arc> / <o-progress>) is present on the page.
Every component is a standard custom element, so it works in plain HTML and in any framework (React, Vue, Svelte, Angular). Import the whole kit, or just the components you use:
import '@zumer/orbit-kit/src/o-gauge.js'
import '@zumer/orbit-kit/src/o-clock.js'| Tag | What it is |
|---|---|
<o-gauge> |
Single-value radial gauge |
<o-donut> |
Data-driven donut / pie chart |
<o-rings> |
Apple-style concentric activity rings |
<o-knob> |
Interactive rotary control (drag / wheel / keys) |
<o-menu> |
Radial / pie menu — single- & multi-level |
<o-instrument> |
Cockpit / dashboard gauges (tach, speedo, fuel, airspeed…) |
<o-clock> |
Analog clock / watch face — the flagship |
<o-compass> |
Heading indicator |
<o-radar> |
Radar / scope display |
Common conventions across the kit:
sizesets the widget's pixel width (square aspect). Components scale Orbit's--o-forceinternally so they actually fill that box.glowis an opt-in neon drop-shadow tinted with the indicator color (gloworglow="12"for the blur radius).data/items/zones/targetstake a JSON array in the attribute.- Set attributes to update live (
el.setAttribute('value', 88)); interactive components also expose JS properties and events.
A single value on an arc, with a center readout.
<o-gauge value="72" unit="%"></o-gauge>
<o-gauge value="125" max="240" label="125 km/h" range="360" glow></o-gauge>| Attribute | Default | Description |
|---|---|---|
value |
0 |
Current value. |
max |
100 |
Value that fills the whole arc. |
range |
270 |
Arc span in degrees (360 = full ring, 180 = semicircle). |
from |
auto | Start angle; defaults so the gap sits at the bottom. |
size |
200px |
Widget width. |
label |
— | Center text; overrides the auto value+unit. |
unit |
"" |
Suffix on the value (%, km/h). |
fill |
#6366f1 |
Progress color. |
track |
#262d38 |
Background ring color. |
stroke-width |
8 |
Ring thickness. |
shape |
rounded |
Arc cap shape (rounded, none). |
glow |
off | Neon glow on the progress arc. |
A donut / pie chart from a JSON data array. Values are normalized to their sum,
or to an explicit total for a partial ring.
<o-donut label="$2.4k"
data='[{"value":52,"color":"#f97316","label":"Rent"},
{"value":28,"color":"#eab308"},
{"value":20,"color":"#22c55e"}]'></o-donut>| Attribute | Default | Description |
|---|---|---|
data |
[] |
[{ value, color?, label? }]. Colors fall back to a palette. |
total |
sum | Denominator; set it for a partial ring (e.g. total="100"). |
range / from |
360 / 0 |
Arc span and start angle. |
stroke-width |
14 |
Ring thickness. |
gap |
2 |
Spacing between segments. |
shape |
none |
Segment caps (none, or rounded to opt in). |
track |
faint | Background ring color. |
label / unit |
— | Center text. |
glow |
off | Neon glow per segment. |
Apple-style concentric activity rings (outer ring first). Each ring gets a dim, solid track in its own color.
<o-rings data='[{"value":80,"color":"#fa114f"},
{"value":55,"color":"#a3ff00"},
{"value":92,"color":"#00fff0"}]'></o-rings>| Attribute | Default | Description |
|---|---|---|
data |
[] |
[{ value, max?, color?, label? }]. |
range / from |
360 |
Arc span and start angle. |
stroke-width |
12 |
Ring thickness. |
step |
1 |
Orbit gap between rings. |
track |
auto | Track color (defaults to a dim wash of each ring's color). |
shape |
rounded |
Cap shape. |
label / unit |
— | Center text. |
glow |
off | Neon glow per ring. |
An interactive rotary control that behaves like a form input.
<o-knob value="65" unit="%" fill="#3da9fc"></o-knob>knob.addEventListener('input', e => console.log(e.detail.value)); // while dragging
knob.addEventListener('change', e => console.log(e.detail.value)); // on release
knob.value = 40; // read / writeDrag vertically, scroll the wheel, or use arrow keys / Page Up·Down / Home·End
when focused. role="slider" + ARIA values are set for you.
| Attribute | Default | Description |
|---|---|---|
value |
min |
Current value. |
min / max |
0 / 100 |
Range. |
step |
1 |
Increment for keys / wheel and snapping. |
range / from |
270 / auto |
Arc span and start angle. |
size |
160px |
Widget width. |
fill |
#a1a1aa |
Value color. |
track |
#27272a |
Track color. |
stroke-width |
14 |
Ring thickness. |
unit / label |
— | Center readout. |
disabled |
off | Non-interactive + dimmed. |
glow |
off | Neon glow on the value arc. |
A radial / pie menu. Items may nest via children for multi-level menus, with
two ways to reveal a branch.
<o-menu label="EDIT" expand="concentric"
items='[
{"label":"Size","icon":"🔠","children":[
{"label":"Bigger","value":"size.up"},
{"label":"Smaller","value":"size.down"}]},
{"label":"Format","icon":"✏️","children":[
{"label":"Bold","value":"fmt.bold"},
{"label":"Italic","value":"fmt.italic"}]},
{"label":"Color","icon":"🎨","value":"color"}]'></o-menu>menu.addEventListener('select', e => e.detail); // { value, label, item, path }
menu.addEventListener('navigate', e => e.detail); // { path, depth }
menu.back(); menu.reset(); menu.path; // navigation API| Attribute | Default | Description |
|---|---|---|
items |
[] |
[{ label, value?, color?, icon?, children? }] (recursive). |
expand |
drill |
drill (ring replaces itself, center = back) or concentric (parent stays, children fan out — the editor look). |
theme |
mono |
mono (slate sectors tinted by accent on hover/active) or color (refined per-item palette). |
accent |
#3da9fc |
Accent for the mono theme. |
range / from |
360 |
Arc span and start angle (270 for a quick action wheel). |
size |
280px |
Widget width. |
gap |
6 |
Spacing between sectors. |
label |
MENU |
Center / breadcrumb text. |
Keyboard: arrows move focus, Enter activates, Esc / Backspace goes back.
Cockpit / dashboard gauges with major + minor ticks, color zones, a redline, a numeric scale, a needle and a digital readout. Driven by presets, or configured by hand.
<o-instrument preset="tachometer" value="6.2"></o-instrument>
<o-instrument preset="airspeed" value="120"></o-instrument>
<o-instrument min="0" max="100" value="40" unit="%" label="LOAD"
zones='[{"from":85,"to":100,"color":"#ef4444"}]'></o-instrument>Presets: tachometer, speedometer, fuel, temp, boost, voltmeter,
airspeed, altimeter, cpu, gpu, vu. Any attribute below overrides the
preset.
| Attribute | Default | Description |
|---|---|---|
value |
min |
Current reading. |
min / max |
0 / 100 |
Scale range. |
range / from |
270 / auto |
Arc span and start angle. |
ticks |
7 |
Major tick / label count. |
minor |
5 |
Minor ticks between each pair of majors. |
zones |
[] |
[{ from, to, color }] color bands (in value units). |
redline |
— | Sugar: a red zone from this value to max. |
tick-labels |
numeric | Custom scale labels, e.g. '["E","½","F"]'. |
unit / label |
— | Readout unit and caption. |
digital |
on | Show the numeric readout. |
case |
auto | round, square, rounded, or bare (auto for ≤180° arcs). |
accent / needle-color / tick-color / face / bezel |
— | Theming. |
size |
240px |
Widget width. |
glow |
off | Neon glow on the needle / zones. |
<o-meter>(a basic speedometer) still ships for back-compat but is superseded by<o-instrument preset="speedometer">.
The flagship: an analog clock / watch face. Live or static, with case shapes, an oval (tonneau) dial, numerals, smartwatch complications, chronograph sub-dials, and an iOS activity-rings face.
<o-clock live seconds></o-clock> <!-- ticking wall clock -->
<o-clock time="10:08:42" numerals="roman" case="square"></o-clock>
<o-clock preset="smartwatch" live brand="ORBIT"></o-clock>
<o-clock preset="chrono" live></o-clock> <!-- tri-compax sub-dials -->
<o-clock case="rectangle" dial="oval" live smooth></o-clock> <!-- tonneau -->
<o-clock dial="rings" live seconds></o-clock> <!-- iOS activity-ring clock -->Presets: classic, roman, minimal, chrono, smartwatch.
| Attribute | Default | Description |
|---|---|---|
time |
now | Static HH:MM[:SS]. Omit for the current time. |
live |
off | Tick with the real clock. |
smooth |
off | Sweeping (not ticking) second hand; implies seconds. |
seconds |
off | Show a second hand. |
numerals |
arabic |
arabic, roman, or none. |
case |
round |
round, square, rounded, rectangle. |
dial |
round |
round, oval (tonneau, matches the case), or rings (iOS face). |
digital / date / brand |
off / off / — | Complications. |
subdials |
off | Chronograph sub-dials (small-seconds / 24h / date). |
accent / hand-color / tick-color / face / bezel / case-bg |
— | Theming (also via CSS vars, e.g. --ok-clock-accent). |
size |
300px |
Widget width. |
glow |
off | Neon glow on the hands. |
A heading indicator: a fixed dial with a top lubber index; the card (ticks +
cardinals) rotates so the current heading sits under the index.
<o-compass heading="045"></o-compass>
<o-compass heading="120" labels="N,NE,E,SE,S,SW,W,NW"></o-compass>| Attribute | Default | Description |
|---|---|---|
heading |
0 |
Heading in degrees (clockwise from North). |
labels |
N,E,S,W |
Cardinal labels (comma-separated). |
fill |
#ef4444 |
Accent (north tick + lubber). |
unit |
° |
Readout suffix. |
size |
220px |
Widget width. |
A radar / scope: concentric range rings, cross-hair spokes, a rotating conic-gradient sweep, and glowing blips.
<o-radar rings="4" spokes="12" label="SCAN"
targets='[{"angle":60,"dist":0.8},
{"angle":200,"dist":0.45},
{"angle":310,"dist":0.65,"color":"#ef4565"}]'></o-radar>| Attribute | Default | Description |
|---|---|---|
targets |
[] |
[{ angle, dist, color? }] — angle °CW from top, dist 0–1. |
rings |
4 |
Concentric range rings. |
spokes |
8 |
Radial cross-hair lines. |
sweep |
on | The rotating beam (sweep="false" to hide). |
sweep-width |
110 |
Beam span in degrees. |
speed |
4 |
Seconds per revolution. |
color |
#22d3ee |
Scope color. |
label |
— | Center label. |
size |
240px |
Widget width. |
orbit-kit components render their structure into the light DOM (not shadow
DOM) on purpose. Orbit positions elements through global CSS (cos() / sin()
/ :has()) and inherited --o-* custom properties, so a layout-composing
component must live in the light DOM for the engine and the cascade to reach it.
The generated markup is exactly the documented Orbit structure — "view source"
stays honest. Inspect any component in devtools to see the rings, satellites and
arcs it expands into.
Everything is theme-able through plain CSS custom properties; the convenience attributes above just map onto them.
Live showcase of every component: zumerlab.com/orbit-kit
(source in docs/index.html).
To run it locally, serve the repo over HTTP so the ES modules load:
npx serve .
# then open /docs/index.htmlModern evergreen browsers. Orbit relies on :has() and CSS trigonometric
functions (cos, sin); the radar/clock visuals use conic-gradient and
color-mix. Orbit shows an upgrade notice on unsupported browsers.