sdxc

[ @sdxc/ui ]

Slider

A single-value range control built on a native <input type="range">, paired with a track that draws its own background rail and a live fill bar.

Equalizer

Gain in decibels, −12 to +12.

+4
60Hz
+1
250Hz
-2
1kHz
+2
4kHz
+5
12kHz
View code
let gains = { "60": 4, "250": 1, "1k": -2, "4k": 2, "12k": 5 };

<Card>
	<Card.Header>
		<Card.Title>Equalizer</Card.Title>
		<Card.Description>Gain in decibels, −12 to +12.</Card.Description>
	</Card.Header>
	<Card.Content>
		{bands.map((band) => (
			<Slider
				key={band.id}
				orientation="vertical"
				min={-12}
				max={12}
				value={gains[band.id]}
				mix={[on<HTMLDivElement, "input">("input", (event) => readGain(band.id, event))]}
			>
				<Slider.Output>{formatGain(gains[band.id])}</Slider.Output>
				<Slider.Track>
					<Slider.Thumb aria-label={`Gain at ${band.label}`} />
				</Slider.Track>
				<Text>{band.label}</Text>
			</Slider>
		))}
	</Card.Content>
</Card>

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

npm add @sdxc/ui remix
import "@sdxc/ui/theme.css";

Usage

import { Slider } from "@sdxc/ui";

Renders the root <div>, stacking its children and resolving range, value, orientation and thumb id into context. Nested parts scope orientation rules to its data-slot, so an ancestor carrying data-orientation (a toolbar, a scroll viewport) leaves its layout alone.

Composition

The parts the component publishes, each a static property of the host.

  • Slider
  • Slider.TrackRenders the visual track: a position: relative <div> that draws a rail and fill bar as pseudo-elements sized from context's resolved value, and overlays a nested Slider.Thumb so native drag spans its full length.
  • Slider.ThumbRenders the interactive thumb: a native <input type="range"> reset to cover Slider.Track's full box so native drag and keyboard control span its whole length, rotating with writing-mode when vertical.
  • Slider.OutputRenders a live readout: a native <output> associated by default with the nearest ancestor Slider's thumb via htmlFor, so assistive technology knows which control it reports on.

Examples

Vertical

View code
let gain = 6;

function readGain(event: Event) {
	if (!(event.target instanceof HTMLInputElement)) return;
	gain = Number(event.target.value);
	void handle.update();
}

<Slider
	orientation="vertical"
	min={0}
	max={10}
	value={gain}
	mix={[on<HTMLDivElement, "input">("input", readGain)]}
>
	<Slider.Track>
		<Slider.Thumb aria-label="Gain at 250 Hz" />
	</Slider.Track>
</Slider>

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeDescription
orientation?"horizontal" | "vertical"Layout axis. Defaults to DEFAULT_ORIENTATION.
min?numberLower bound of the range. Defaults to DEFAULT_MIN.
max?numberUpper bound of the range. Defaults to DEFAULT_MAX.
value?numberCurrent value, for a slider whose value the consumer tracks itself.
defaultValue?numberStarting value, for a slider that never tracks its own value.

Also accepts everything in TagProps<"div">.

Slider.Track

Also accepts everything in TagProps<"div">.

Slider.Thumb

Also accepts everything in Omit<TagProps<"input">, "type" | "role">.

Slider.Output

Also accepts everything in TagProps<"output">.

Types

NameValuesWhat it decides
Orientation"horizontal" | "vertical"Axis the track's fill bar and thumb travel along: a full-width row, or a full-height column.

Written by Sergio Xalambrí. Follow @sergiodxa for new packages, or sponsor the work.