Forms
Slider
A labeled slider on the Field contract: pass label, and a defaultValue (or value with onValueChange). A value array, defaultValue={[20, 80]}, gives a range with a thumb per value. showValue shows the value, formatted with format. Each thumb has a 44px touch area on phones.
Install
Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):
npx shadcn@latest init --base base --preset nova --yes --no-monoreponpx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):
npx shadcn@latest add ourostack/ouro-ui/slider#v1.2.13Or, with the @ouro namespace set up:
npx shadcn@latest add @ouro/ouro-base @ouro/sliderIts tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):
npx shadcn@latest add ourostack/ouro-ui/slider#v1.2.13 ourostack/ouro-ui/slider-tests#v1.2.13import { Slider } from "@/components/ouro/slider/slider";Paths use shadcn's default @/ alias; the CLI rewrites them to yours.
Example
<Slider label="Servings" name="servings" defaultValue={4} min={1} max={12} showValue />
<Slider label="Price" name="price" defaultValue={[10, 40]} format={{ style: "currency", currency: "USD" }} showValue />Use instead when
- Use
NumberFieldinstead when people need an exact number, andRadioGroupfor a few named choices.
Props
Type: SliderProps<Value>.
className- Type:
string - Layout only: margins, width, grid placement (
mt-4,col-span-2). Appearance classes warn in development; style sliders in your theme. defaultValue- Type:
Value - The starting value, when the slider keeps its own. An array gives a range:
defaultValue={[20, 80]}. description- Type:
ReactNode - Supporting text under the label, read after the label through
aria-describedby. disabled- Type:
boolean - Disables the slider and fades it.
error- Type:
ReadonlyErrorMessages - What is wrong, from your server action or client check. The message (or several, as a list) shows under the slider, which gets
aria-invalidand the destructive color. A message is text or a React node (one with a link); an empty string or array means valid. format- Type:
Intl.NumberFormatOptions - How the value reads, as
Intl.NumberFormatoptions, forshowValueand screen readers:{ style: "percent" },{ style: "currency", currency: "EUR" }. hideLabel- Type:
boolean - Hides the label visually; screen readers still read it as the slider's name.
label(required)- Type:
string - What the slider sets, shown above it and read as its name. Required: every control needs a name. To hide it visually, keep it and add
hideLabel. largeStep- Type:
number - Default:
10 - The step for Page Up, Page Down and Shift with an arrow key.
locale- Type:
Intl.LocalesArgument - Default: the browser's, once hydrated; en-US in the server's HTML
- The locale for
format. max- Type:
number - Default:
100 - The highest value.
min- Type:
number - Default:
0 - The lowest value.
name- Type:
string - The form field name the value submits under; a range submits one entry per thumb.
onValueChange- Type:
((value: SliderOutput<Value>) => void) - Called with the new value as the user drags, presses the track or uses the keyboard: a number, or an array for a range.
onValueCommitted- Type:
((value: SliderOutput<Value>) => void) - Called once the user lets go (or with each key press), with the final value. Use it to save.
ref- Type:
Ref<HTMLInputElement> - The first thumb's
<input type="range">. showValue- Type:
boolean - Shows the formatted value at the end of the slider; a range shows both ends:
$10 – $40. step- Type:
number - Default:
1 - The distance between values.
thumbLabels- Type:
readonly string[] - Default: ["Minimum", "Maximum"]
- What each thumb of a range is called, before the label: screen readers hear "Minimum, Price". Translate them with your app.
value- Type:
Value - The value, when you control it. An array gives a thumb per value:
value={[20, 80]}is a range.
Don't use
These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.
errorMessage: Not a prop. Ouro UI useserror:<Slider error="Required.">.helperText: Not a prop. Ouro UI usesdescription:<Slider description="...">.invalid: Not a prop.errormarks the slider invalid:<Slider error="What is wrong">.isDisabled: Not a prop. Ouro UI usesdisabled:<Slider disabled>.isInvalid: Not a prop.errormarks the slider invalid:<Slider error="What is wrong">.isRequired: Not a prop. A slider always has a value, so it is never missing:<Slider defaultValue={50}>.maxValue: Not a prop. Ouro UI usesmax:<Slider max={10}>.minValue: Not a prop. Ouro UI usesmin:<Slider min={1}>.onChange: Not a prop. Slider reports the value itself:<Slider onValueChange={(value) => …}>.range: Not a prop. A value array gives a thumb per value:<Slider defaultValue={[20, 80]}>.required: Not a prop. A slider always has a value, so it is never missing:<Slider defaultValue={50}>.showTooltip: Not a prop. Ouro UI usesshowValue:<Slider showValue>.valueLabelDisplay: Not a prop. Ouro UI usesshowValue:<Slider showValue>.
className is for layout only
Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: Slider merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes
Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.
Alignment classes (text-center) warn too: set alignment on a parent element.
Types
ErrorMessage
One error message: text, or a React element for a message that carries a link or other markup.
type ErrorMessage = string | ReactElement;ReadonlyErrorMessages
A read-only message view accepted by fields and Form; mutable input arrays remain valid.
type ReadonlyErrorMessages = ErrorMessage | readonly ErrorMessage[];SliderOutput
The value Slider reports: a number for one thumb, an array for a range.
type SliderOutput<Value extends SliderValue> = Value extends readonly number[] ? number[] : number;SliderValue
A slider's value: one number, or one per thumb for a range.
type SliderValue = number | readonly number[];Claim sources
- layout-classes: test:registry/ouro/components/ouro/slider/slider.test.tsx::Slider > lets app layout classes win on the root
verify:testExists(registry/ouro/components/ouro/slider/slider.test.tsx::Slider > lets app layout classes win on the root)