Slider

A value set roughly between two bounds (range slider): a share of traffic, an alert threshold, weekly hours. The position on the track says as much as the figure.

import { Slider } from "@umriss-ui/core";

onChange reports a number already on the step and inside the bounds, by pointer and by key alike. Pair it with a NumberInput on the same state when the exact figure matters too.

Examples

Slider

Use a slider for a value set roughly between two bounds; step sets how finely it moves.

import { FormField, Slider } from "@umriss-ui/core";

export default function CanaryTraffic() {
  return (
    <FormField label="Canary traffic, %" hint="Share of requests the new release receives." style={{ maxWidth: 360 }}>
      <Slider min={0} max={100} step={5} defaultValue={10} />
    </FormField>
  );
}

Units and marks

format writes the value for the readout and the screen reader; marks show reference values, with a word where one has a label.

import { FormField, Grid, Slider } from "@umriss-ui/core";

export default function UnitsAndMarks() {
  return (
    <Grid minItemWidth="260px" gap={6}>
      <FormField label="Alert above error rate">
        <Slider
          min={0}
          max={5}
          step={0.1}
          defaultValue={1.5}
          format={(v) => `${v.toFixed(1)} %`}
          marks={[0, { value: 1, label: "Objective" }, 5]}
        />
      </FormField>
      <FormField label="Log retention" hint="30 days, fixed by the data protection policy.">
        <Slider min={7} max={90} defaultValue={30} disabled showValue={false} marks={[7, 30, 90]} />
      </FormField>
    </Grid>
  );
}

Set roughly, then exactly

Control it with value and onChange and put a NumberInput beside it on the same state for the exact figure.

import { useState } from "react";
import { FormField, NumberInput, Slider, Stack } from "@umriss-ui/core";

export default function SetRoughlyThenExactly() {
  const [hours, setHours] = useState(32);

  return (
    <Stack gap={3} style={{ maxWidth: 420 }}>
      <FormField label="Weekly capacity, Kofi Mensah">
        <Slider
          min={0}
          max={48}
          value={hours}
          onChange={setHours}
          showValue={false}
          format={(v) => `${v} h`}
          marks={[{ value: 0, label: "0" }, { value: 40, label: "Full time" }, { value: 48, label: "48" }]}
        />
      </FormField>
      <FormField label="Exact hours">
        <NumberInput value={hours} onChange={(v) => setHours(v ?? 0)} min={0} max={48} decimals={0} suffix="h" />
      </FormField>
    </Stack>
  );
}

Split a budget

Several sliders share one whole; show the sum they make in words, since no single slider can say it.

import { useState } from "react";
import { Badge, Card, CardBody, CardHeader, FormField, Slider, Stack, Text, useFormats } from "@umriss-ui/core";

const CHANNELS = [
  { id: "search", label: "Search ads", plan: 45 },
  { id: "events", label: "Events", plan: 30 },
  { id: "content", label: "Content", plan: 25 },
];

const BUDGET = 68_000;

export default function SplitABudget() {
  const formats = useFormats();
  const [shares, setShares] = useState<Record<string, number>>({ search: 45, events: 35, content: 25 });
  const sum = CHANNELS.reduce((total, c) => total + (shares[c.id] ?? 0), 0);

  return (
    <Card style={{ maxWidth: 560 }}>
      <CardHeader
        eyebrow="CC-1200 Marketing · April"
        title={`Budget ${formats.number(BUDGET, 0)} €`}
        actions={<Badge tone={sum === 100 ? "success" : "warning"}>{sum === 100 ? "Adds up to 100 %" : `Sum ${sum} %`}</Badge>}
      />
      <CardBody>
        <Stack gap={5}>
          {CHANNELS.map((c) => (
            <FormField key={c.id} label={c.label}>
              <Slider
                step={5}
                value={shares[c.id] ?? 0}
                onChange={(v) => setShares((previous) => ({ ...previous, [c.id]: v }))}
                format={(v) => `${v} % · ${formats.number((BUDGET * v) / 100, 0)} €`}
                marks={[0, 50, 100, { value: c.plan, label: "Plan" }]}
              />
            </FormField>
          ))}
          <Text size="xs" tone="muted">
            The plan was agreed in the March review.
          </Text>
        </Stack>
      </CardBody>
    </Card>
  );
}

When to use something else

Keyboard

Key Action
Arrow Right / Arrow Up Increases the value by one step.
Arrow Left / Arrow Down Decreases the value by one step.
Page Up / Page Down Moves by a tenth of the range.
Home / End Moves to the lower or upper bound.

API

SliderProps

NameTypeDefaultDescription
defaultValuenumberminUncontrolled: the value to start at.

Shown in: Configurator, Slider, Units and marks

valuenumber—Controlled: the value.

Shown in: Set roughly, then exactly, Split a budget, Browse down and back up (Breadcrumb) and 2 more

minnumber0The smallest value.

Shown in: Configurator, Slider, Units and marks and 4 more

maxnumber100The largest value.

Shown in: Configurator, Slider, Units and marks and 4 more

stepnumber1The step the value moves by, by pointer or key.

Shown in: Configurator, Slider, Units and marks and 3 more

marksreadonly SliderMark[]—Values marked on the track; an object with a label writes the word beneath its mark. A mark shows a value, it does not catch the thumb.

Shown in: Units and marks, Set roughly, then exactly, Split a budget and 1 more

format(value: number) => stringthe number in the formats' notation, with as many decimals as the step hasThe value as text: for the readout and for the screen reader (aria-valuetext).

Shown in: Units and marks, Set roughly, then exactly, Split a budget and 3 more

showValuebooleantrueThe value in mono beside the track.

Shown in: Configurator, Units and marks, Set roughly, then exactly and 1 more

refRef<HTMLInputElement>—Receives the component's root element. from RefProp

Shown in: A row that holds still (Sizes), An anchored surface (Popover), Take the width of the trigger (Popover) and 2 more

Events

NameTypeDefaultDescription
onChange(value: number) => void—Reports every change, by pointer or key, as a number on the step.

Shown in: Set roughly, then exactly, Split a budget, Browse down and back up (Breadcrumb) and 2 more

Also takes every attribute of <input> – without defaultValue, max, min, onChange, step, type, value.

Types on this page

SliderMark

A mark on the track: a value, or a value with the word beneath it.

type SliderMark = number | { value: number; label?: ReactNode };

Known limits

What umriss deliberately does not build, and why: ADR-0032.

Every page of @umriss-ui/core

Getting started

Customising

Layout

Typography

Actions

Forms

Choosing

Dates and times

Feedback

Overlays

Navigation

Data display

API index