Slider
Adjust a value along a track, with a bound label and readout.

use blinc_cn as cn;
use blinc_core::reactive::Signal;
use blinc_layout::prelude::*;
pub fn slider_demo(value: Signal<f32>, disabled: Signal<bool>, viewport: (f32, f32)) -> Div {
let number = value;
div().class("demo-wide").child(
cn::slider(number)
.label("Volume")
.min(0.0)
.max(100.0)
.step(1.0)
.show_value()
.w((viewport.0 - 64.0).clamp(1.0, 360.0))
.disabled(disabled),
)
}
@layer components {
.cn-slider-field {
font-family: var(--font-sans);
}
.cn-slider:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
.cn-slider {
border-radius: var(--radius-full);
cursor: pointer;
outline: 2px solid transparent;
outline-offset: 2px;
}
.cn-slider[data-focus-visible] {
outline-color: var(--focus-ring);
}
.cn-slider-fill {
background: var(--cn-slider-fill-bg, var(--primary));
border-radius: var(--radius-full) 0 0 var(--radius-full);
}
.cn-slider-rest {
background: var(--cn-slider-track-bg, var(--border));
border-radius: 0 var(--radius-full) var(--radius-full) 0;
}
.cn-slider-thumb {
background: var(--cn-slider-thumb-bg, var(--text-inverse));
border: 2px solid var(--primary);
border-radius: var(--radius-full);
box-shadow: var(--shadow-sm);
transition: transform var(--duration-fast) var(--ease-state),
border-color var(--duration-fast) var(--ease-state);
}
.cn-slider:hover:not(:disabled) > .cn-slider-thumb {
transform: scale(1.1);
box-shadow: var(--shadow-md);
border-color: var(--primary-hover);
}
.cn-slider:active:not(:disabled) > .cn-slider-thumb,
.cn-slider[data-state="dragging"] > .cn-slider-thumb {
transform: scale(1.2);
}
.cn-slider:disabled {
cursor: not-allowed;
}
.cn-slider:disabled > .cn-slider-rest {
background: var(--input-bg-disabled);
}
.cn-slider:disabled > .cn-slider-fill {
background: var(--border-secondary);
}
.cn-slider:disabled > .cn-slider-thumb {
background: var(--input-bg-disabled);
border: 1px solid var(--border-secondary);
box-shadow: none;
}
.cn-slider-label {
color: var(--text-primary);
}
.cn-slider-value {
color: var(--text-secondary);
}
.cn-slider-field[data-disabled] .cn-slider-label,
.cn-slider-field[data-disabled] .cn-slider-value {
color: var(--text-tertiary);
}
}
Usage and properties
Adjust a value along a track, with a bound label and readout. Apply CSS after the component layer to restyle the documented parts.
Use the installation guide to add blinc_cn and its component stylesheet. Create the fixture bindings once, and return the demo from your UI builder. Values marked Bound accept Signal/Computed sources where the API supports them; structural options configure the component at construction.
| Property | Type | Update model | This example |
|---|---|---|---|
value | Signal<f32> | Bound | 42 |
min / max / step | numbers | Construction | 0 / 100 / 1 |
show_value | builder flag | Construction | enabled |
disabled | bool or IntoReactive<bool> | Bound | values.disabled |
Keyboard and interaction
Tab focuses the slider. Arrow keys, Page Up and Page Down, Home and End move it; values snap to the step. :focus-visible marks keyboard focus.
Customizing it
Add application CSS after the default component layer. These selectors are the restyling surface for this component:
.cn-slider.cn-slider-header.cn-slider-field.cn-slider-fill.cn-slider-rest.cn-slider-thumb
Theme and component variables: --primary, --text-primary, --text-secondary, --surface, --border, --radius-default, --duration-fast, --ease-state.
Built-in themes
The Live theme control installs Blinc's own theme bundles, including their colours, focus rings, corner shapes and motion tokens.
pub fn theme_bundle_for(name: &str) -> blinc_theme::ThemeBundle {
match name {
"restrained" => blinc_theme::RestrainedTheme::bundle(),
"expressive" => blinc_theme::ExpressiveTheme::bundle(),
_ => blinc_theme::HybridTheme::bundle(),
}
.with_css(blinc_cn::cn_styles::CN_STYLES)
}Download the default widget and component stylesheets. Sample assets and licenses are available in the asset guide.
Documentation
From the canonical component guide.
A number picked along a track, bound to a Signal<f32> or Signal<f64>:
let volume = ctx.use_signal(50.0);
cn::slider(volume)
.min(0.0)
.max(100.0)
.step(1.0)
.label("Volume")
.show_value()
.on_change(|value| println!("volume: {value}"))
Click where you want it or drag the thumb; the wheel steps it, and after a
click the arrow keys, Page Up/Down and Home/End move it too. Without a step,
an arrow or wheel step moves a hundredth of the range. .size(SliderSize::Small)
sets the size, .w(px) the track's length (300px unless set), and
.disabled(..) takes a bool, Signal or Computed and follows it in place.
The label and live value form one adjustable element in the accessibility snapshot. Assistive adjustment uses the same step, bounds and change callback; disabled sliders reject it.
The slider is a .cn-slider row of .cn-slider-fill, .cn-slider-thumb and
.cn-slider-rest, inside a .cn-slider-field with a .cn-slider-header
(.cn-slider-label, .cn-slider-value) when it has a label or shows its value.
Colours are those rules; --cn-slider-fill-bg, --cn-slider-track-bg and
--cn-slider-thumb-bg recolour one. The thumb grows under the pointer and more
while held, and a disabled slider carries disabled:
.cn-slider:disabled > .cn-slider-fill { background: var(--border); }
For two ends on one control, use a Number Range Gauge.
Platforms and version
The component API is available in Blinc 0.6.0. The Live example runs in a dedicated worker and requires a compatible GPU surface. Preview and Code remain available when Live cannot start. The canvas has a descriptive label; a full screen-reader DOM mirror is not provided. The gallery integration is based on revision e2e55c24e078.
Recordings and live demos use the default Hybrid theme with bundled Noto Sans. The recording uses a 560 × 320 logical viewport at twice that resolution. Live follows its container and actual display density. Source base revision · Exact build source · Artifact versions and checksums · Font license.