Progress#
Component <neo-progress> is the read-only sibling of <neo-slider>: same rail, fill, and anchor-mark styling, shared --neo-slider-* tokens, but no thumb, keyboard, or editable readout.
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
Reference#
Attributes #
| Name | Type | Default | Description |
|---|---|---|---|
value | number | none | Clamped to [min, max]. |
min | number | 0 | Lower bound. |
max | number | 100 | Upper bound. |
label | string | none | Plain-text caption. |
unit | string | none | Plain-text suffix on the value display. |
hide-value | boolean | false | Suppress the value display. |
vertical | boolean | false | Switch to vertical orientation. |
indeterminate | boolean | false | Looping animation for unknown-duration tasks. |
easing | string | none | CSS transition shorthand for the fill animation. |
Slots #
| Name | Description |
|---|---|
[data-neo-progress-mark] | Anchor mark at a numeric value, optionally with a label child. |
Parts #
| Name | Description |
|---|---|
::part(header) | Row holding the label, value, and unit. |
::part(label) | Label text. |
::part(output) | Wrapper around the value and unit. |
::part(value) | Value text. |
::part(unit) | Unit suffix after the value. |
::part(track) | The rail behind the fill. |
::part(fill) | Painted progress segment. |
::part(marks) | Container for anchor-mark labels below the track. |
CSS variables #
| Name | Default | Description |
|---|---|---|
--neo-progress-fill-bg | var(--neo-slider-fill-bg, var(--accent)) | Fill color. |
--neo-progress-fill-transition | none | Transition applied to the fill when the value changes. |
--neo-progress-indeterminate-duration | calc(1.4s * var(--neo-duration-scale, 1)) | Cycle duration of the indeterminate animation. |
Examples#
Marks with labels#
Same slot convention as the slider: <span data-neo-progress-mark="…"> children render an anchor dot at the value plus a label beneath. The dot and label flip to their active colour once the bar's value reaches them.
Dense mark labels#
Labels that overlap or sit less than 1ch apart collapse automatically. Hover a hidden label or its nearby rail position to reveal it. The highest active mark stays visible as the value moves.
Bare rail#
Omit label and set hide-value to drop the header entirely. The marks row still hides itself when no mark carries a label, so this collapses to just the bar.
Indeterminate#
Set indeterminate and a 35% segment slides along the rail in a loop for unknown-duration tasks. The value attribute is ignored while it's on, and the track drops its aria-valuenow so AT announces it as indeterminate. Honours prefers-reduced-motion.
Custom indeterminate animation#
The rail lives in the shadow root, so reach the fill across the boundary with ::part(fill), then override animation from a per-instance class to swap the kit's default left-to-right loop for any custom keyframe. This one widens the segment to half the rail and ping-pongs from end to end.
Vertical#
Set vertical to rotate the bar. Min sits at the bottom, max at the top. Use it for capacity meters where the height of the fill maps to the quantity.
Examples: Datastar#
Morphing during interaction#
A Datastar app can fat-morph the page at any moment; a server reporting progress just re-emits the bar with a new value. The painted rail lives in the component's shadow root, so a morph of the light host only changes the value attribute and never touches the fill node, letting the easing transition ease the fill to the new value. Autoplay cycles the states below, with no signals or morph hints, and the fill eases backward from 40% to 0% on the wrap just the same.
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
Server-driven downloads#
Clicking Download opens an SSE connection to /progress/download. Each sse.patchSignals bumps the value signal by 25% on a one-second beat; the bar's data-attr:value binding renders the change without re-emitting the host. A final patch flips the bar's label through the same signal; its data-attr:label binding renders "Done ✓" inside the component's frame; the rail is in the shadow root, so the success state rides the label attribute rather than a separate status row.