Skip to main content
On this pageFunctions

Ui/Slider

Functions

fractionOfValue

functionsource
/**
 * Computes the fraction (0–1) of a value between min and max. Returns 0 when
 *  the range has zero width.
 */
(model: Slider.Model): number

init

functionsource
/**
 * Creates an initial slider model from a config. The initial value is
 *  snapped to the step and clamped into range.
 */
(config: InitConfig): Slider.Model

subscriptionsForRoot

functionsource

update

functionsource
/**
 * Processes a slider message and returns the next model, commands, and an
 *  optional out-message for the parent.
 */
(
  model: Slider.Model,
  message: {
    _tag: "PressedThumb"
  } | {
    _tag: "PressedPointer"
    value: number
  } | {
    _tag: "MovedDragPointer"
    value: number
  } | {
    _tag: "ReleasedDragPointer"
  } | {
    _tag: "CancelledDrag"
  } | {
    _tag: "PressedKeyboardNavigation"
    direction: "Max" | "Min" | "StepDecrement" | "StepIncrement" | "PageDecrement" | "PageIncrement"
  }
): UpdateReturn

Types

CancelledDrag

typesource
/** Escape was pressed during a drag. Restores the value from the drag origin. */
type CancelledDrag = CallableTaggedStruct<"CancelledDrag", {}>

InitConfig

typesource
/** Configuration for creating a slider model with `init`. */
type InitConfig = Readonly<{
  id: string
  initialValue: number
  max: number
  min: number
  step: number
}>

MovedDragPointer

typesource
/**
 * The pointer moved during a drag, producing a new snapped value from the
 *  cursor position within the track.
 */
type MovedDragPointer = CallableTaggedStruct<"MovedDragPointer", {
  value: Number
}>

PressedKeyboardNavigation

typesource
/** The user pressed a keyboard navigation key on the focused thumb. */
type PressedKeyboardNavigation = CallableTaggedStruct<"PressedKeyboardNavigation", {
  direction: Literals<readonly ["StepDecrement", "StepIncrement", "PageDecrement", "PageIncrement", "Min", "Max"]>
}>

PressedPointer

typesource
/**
 * The user pressed the track. Starts a drag and snaps the value to the
 *  cursor position. Ignored while already dragging, which absorbs the bubble
 *  from a thumb press so the value is not shifted.
 */
type PressedPointer = CallableTaggedStruct<"PressedPointer", {
  value: Number
}>

PressedThumb

typesource
/** The user pressed the thumb. Starts a drag without changing the value. */
type PressedThumb = CallableTaggedStruct<"PressedThumb", {}>

ReleasedDragPointer

typesource
/** The pointer was released during a drag. Commits the current value. */
type ReleasedDragPointer = CallableTaggedStruct<"ReleasedDragPointer", {}>

SliderAttributes

typesource
/**
 * Attribute groups the slider component provides to the consumer's `toView`
 *  callback. Each bundle carries the boundary's captured dispatch, so the
 *  consumer can spread it directly into element attributes without manual
 *  Message wrapping.
 */
type SliderAttributes = Readonly<{
  filledTrack: ReadonlyArray<ChildAttribute>
  hiddenInput: ReadonlyArray<ChildAttribute>
  label: ReadonlyArray<ChildAttribute>
  root: ReadonlyArray<ChildAttribute>
  thumb: ReadonlyArray<ChildAttribute>
  track: ReadonlyArray<ChildAttribute>
}>

ViewInputs

typesource
/** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field. */
type ViewInputs = Readonly<{
  ariaLabel: string
  ariaLabelledBy: string
  formatValue: (value: number) => string
  getTrackRoot: () => Document | ShadowRoot
  isDisabled: boolean
  name: string
  toView: (attributes: SliderAttributes) => Html
}>

Constants

Message

constsource
/** Union of all messages the slider component can produce. */
const Message: S.Union<[typeof PressedThumb, typeof PressedPointer, typeof MovedDragPointer, typeof ReleasedDragPointer, typeof CancelledDrag, typeof PressedKeyboardNavigation]>

Model

constsource
/**
 * Schema for the slider component's state. Tracks the current value, the
 *  range (min/max/step), and the active drag phase.
 */
const Model: Struct<{
  dragState: Union<readonly [
    CallableTaggedStruct<"Idle", {}>,
    CallableTaggedStruct<"Dragging", {
      originValue: Number
    }>
  ]>
  id: String
  max: Number
  min: Number
  step: Number
  value: Number
}>

OutMessage

constsource
/** Union of all out-messages the slider component can emit to its parent. */
const OutMessage: Union<readonly [
  CallableTaggedStruct<"ChangedValue", {
    value: Number
  }>
]>

reflectRange

constsource
/**
 * Reflects an externally-driven range onto the slider. Snaps and clamps the
 *  current value into the new range. Use this when min/max derive from
 *  external state (e.g. a bounded buffer whose first/last index shifts over
 *  time). Unlike `reflectValue`, this runs even while the user is Dragging: a
 *  structural range change cannot leave the value out of bounds.
 */
const reflectRange: Reflect<Model, Readonly<{
  max: number
  min: number
}>>

reflectValue

constsource
/**
 * Reflects an externally-driven value onto the slider, snapped and clamped
 *  into range; a no-op while the user is dragging, since drag state owns the
 *  value. Does not emit `ChangedValue`; use when the value is being driven by
 *  external state rather than user input.
 */
const reflectValue: Reflect<Model, number>

subscriptions

constsource
/** Default drag subscriptions, with the track looked up via `document`. */
const subscriptions: {
  dragEscape: EntryWithoutKeepAlive<Slider.Model, {
    _tag: "PressedThumb"
  } | {
    _tag: "PressedPointer"
    value: number
  } | {
    _tag: "MovedDragPointer"
    value: number
  } | {
    _tag: "ReleasedDragPointer"
  } | {
    _tag: "CancelledDrag"
  } | {
    _tag: "PressedKeyboardNavigation"
    direction: "Max" | "Min" | "StepDecrement" | "StepIncrement" | "PageDecrement" | "PageIncrement"
  }, {
    dragActivity: "Idle" | "Active"
  }, never> & SubscriptionBrand
  dragPointer: EntryWithoutKeepAlive<Slider.Model, {
    _tag: "PressedThumb"
  } | {
    _tag: "PressedPointer"
    value: number
  } | {
    _tag: "MovedDragPointer"
    value: number
  } | {
    _tag: "ReleasedDragPointer"
  } | {
    _tag: "CancelledDrag"
  } | {
    _tag: "PressedKeyboardNavigation"
    direction: "Max" | "Min" | "StepDecrement" | "StepIncrement" | "PageDecrement" | "PageIncrement"
  }, {
    dragActivity: "Idle" | "Active"
    id: string
    max: number
    min: number
  }, never> & SubscriptionBrand
}

view

constsource
/**
 * Renders an accessible slider by building ARIA attribute groups and
 *  delegating layout to the consumer's `toView` callback. Follows the
 *  WAI-ARIA slider pattern: role="slider" on the thumb, aria-valuemin /
 *  aria-valuemax / aria-valuenow, keyboard navigation by step / page / home /
 *  end. Pointer drag is handled by the component's drag subscriptions.
 */
const view: SubmodelView<Slider.Model, {
  _tag: "PressedThumb"
} | {
  _tag: "PressedPointer"
  value: number
} | {
  _tag: "MovedDragPointer"
  value: number
} | {
  _tag: "ReleasedDragPointer"
} | {
  _tag: "CancelledDrag"
} | {
  _tag: "PressedKeyboardNavigation"
  direction: "Max" | "Min" | "StepDecrement" | "StepIncrement" | "PageDecrement" | "PageIncrement"
}, Readonly<{
  ariaLabel: string
  ariaLabelledBy: string
  formatValue: (value: number) => string
  getTrackRoot: () => Document | ShadowRoot
  isDisabled: boolean
  name: string
  toView: (attributes: SliderAttributes) => Html
}>>

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson