Skip to content
  1. Keyline UI
  2. Slider
Keyline UIComponents
  • Get started
    • Installation
    • Theming
    • Modes
    • Configuration
    • Composition
  • Actions
    • Button
    • Button group
    • Split button
    • Toggle
    • Toggle group
    • Toolbar
    • Menu
    • Menubar
    • Context menu
  • Inputs
    • Field and form
    • Checkbox
    • Checkbox group
    • Radio group
    • Switch
    • Slider
    • Segmented
    • Select
    • Native select
    • Combobox
    • Multiselect
    • Number field
    • OTP field
    • Time field
    • Date picker and calendar
    • Date range
  • Data
    • Table
    • Chart
    • Stat and meter
    • Status and badge
    • Progress
    • Skeleton
    • Empty
    • Avatar
    • Kbd
    • Marker
  • Navigation
    • Tabs
    • Breadcrumb
    • Pagination
    • Nav
    • Navigation menu
    • Command menu
  • Overlays
    • Dialog
    • Alert dialog
    • Drawer
    • Sheet
    • Popover
    • Hover card
    • Tooltip
    • Toast
    • Notice
  • Layout
    • App shell
    • Sidebar
    • Panel
    • Resizable
    • Scroll area
    • Accordion
    • Collapsible
    • Carousel
    • Inspector
    • Item
    • Direction
  • Conversation
    • Message
    • Bubble
    • Message scroller
    • Attachment
    • Questionnaire
  • Blocks
    • Shipments

Slider

A value on a scale, in a frame with a readout cell. The readout is sized for the longest value it can show, so the frame never shifts while you drag.

Loading the live example…

"use client"

import { useState } from "react"
import { Slider } from "@/components/keyline/ui/slider"

const ORDER = 12_400 // Lackawanna County's annual paper order, in dollars
const usd = (n: number) => n.toLocaleString("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0 })

export function CountyDiscount() {
  const [pct, setPct] = useState(6)
  const needsMichael = pct > 10

  return (
    <div className="grid max-w-[440px] gap-3">
      <Slider
        label="Discount for Lackawanna County"
        unit="%"
        min={0}
        max={15}
        value={pct}
        onValueChange={(v) => setPct(v as number)}
        description="Over 10% needs Michael's sign-off."
      />
      <p role="status" className="text-[14px] text-kl-ink-2">
        {usd((ORDER * pct) / 100)} off {usd(ORDER)}: they pay {usd(ORDER - (ORDER * pct) / 100)}.
        {needsMichael ? " Michael has to approve this one." : ""}
      </p>
    </div>
  )
}

Installation

npx shadcn@latest add @keyline-ui/slider

Run it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.

Usage

import { Slider } from "@/components/keyline/ui/slider"
<Slider label="Discount" unit="%" min={0} max={15} value={pct} onValueChange={setPct} />

Examples

Range

Pass two numbers for two thumbs. The fill runs between them, and each thumb is named “from” or “to”. format prints the readout as currency.

Loading the live example…

"use client"

import { useState } from "react"
import { Slider } from "@/components/keyline/ui/slider"

const PAPER = [
  { name: "20 lb copy", price: 42 },
  { name: "24 lb premium", price: 58 },
  { name: "Recycled 20 lb", price: 47 },
  { name: "110 lb cardstock", price: 96 },
  { name: "Resume paper, ivory", price: 74 },
]

export function PriceRange() {
  const [range, setRange] = useState<number[]>([40, 80])
  const [lo, hi] = range
  const shown = PAPER.filter((p) => p.price >= lo && p.price <= hi)

  return (
    <div className="grid max-w-[440px] gap-3">
      <Slider label="Price per case" locale="en-US" format={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }} min={20} max={120} step={5} value={range} onValueChange={(v) => setRange(v as number[])} />
      <ul className="m-0 grid list-none gap-1 p-0 text-[14px]" aria-label="Paper in range">
        {shown.map((p) => (
          <li key={p.name} className="flex justify-between gap-4">
            <span>{p.name}</span>
            <span className="tabular-nums text-kl-ink-2">${p.price}</span>
          </li>
        ))}
      </ul>
      <p role="status" className="text-[14px] text-kl-ink-2">
        {shown.length ? `${shown.length} of ${PAPER.length} papers.` : "Nothing in that range. Widen it or ask Dwight what's in the warehouse."}
      </p>
    </div>
  )
}

Props

PropTypeDefaultDescription
labelReactNodeDefault —Names the slider and every thumb. Required.
valuenumber | number[]Default —Two numbers make a range with two thumbs. With onValueChange, or start with defaultValue.
min / max / stepnumberDefault 0 / 100 / 1The scale. The readout is sized for its longest value.
unitReactNodeDefault —Printed after the value in the readout, and read out with it.
formatIntl.NumberFormatOptionsDefault —Formats the readout, such as currency. Pair it with locale.
showValuebooleanDefault trueHide the readout only when the text around it already prints the value.
errorReactNodeDefault —The message when a check fails. With invalid it always shows.
descriptionReactNodeDefault —A line under the field, read out with it.
layout"control" | "cell"Default "control"cell drops the frame and hides the label, to sit inside another frame.

Arrow keys step, Page Up and Down take a larger step, Home and End jump to the ends. In a right-to-left page the scale mirrors. Built on Base UI Slider.

Sheet 21 of 73PreviousSwitchNextSegmented
On this page