Skip to content
Suluu

RopeTimePicker

A precise analog picker with softly weighted rope hands. Drag the hour, minute, or second dots, or edit the digital fields without giving up the calm physical character.

Preview

Drag a rope dot or edit the digits

Installation

Registry — recommended

Copies the component into your configured shadcn UI directory and installs Motion.

npx shadcn@latest add https://suluu.site/r/rope-time-picker.json

npm package

For centralized upgrades, install the optional ESM package and configure Tailwind source detection as shown below.

pnpm add suluu motion

Usage

RopeTimePicker uses a focused twelve-hour value with explicit AM or PM. Use defaultValue for local state, or pair value with onValueChange when your application owns the time.

Registry
import { RopeTimePicker } from "@/components/ui/rope-time-picker"

export function AlarmTime() {
  return (
    <RopeTimePicker
      defaultValue={{ hours: 7, minutes: 30, seconds: 0, period: "AM" }}
      onValueChange={(time) => saveAlarm(time)}
    />
  )
}
npm
// app/globals.css
@import "suluu/styles.css";
@source "../node_modules/suluu/dist";

// component.tsx
import { RopeTimePicker } from "suluu/rope-time-picker"

export function AlarmTime() {
  return <RopeTimePicker />
}

Controlled time and seconds

Seconds stay in the value even when hidden, so hour and minute edits never discard application state.

Controlled
const [time, setTime] = useState({
  hours: 9,
  minutes: 35,
  seconds: 20,
  period: "AM" as const,
})

<RopeTimePicker
  onValueChange={setTime}
  showSeconds
  value={time}
/>

Controlled mode

Mode normally follows the field or rope point the user chooses. Control it when another part of your interface needs to coordinate the active unit.

Mode
const [mode, setMode] = useState<"hour" | "minute" | "second">("hour")

<RopeTimePicker
  mode={mode}
  onModeChange={setMode}
  showSeconds
/>

Five-minute steps

One-unit snapping is the default. Use five-unit snapping for scheduling surfaces where quick selection matters more than minute-by-minute granularity.

Stepped
<RopeTimePicker
  defaultValue={{ hours: 10, minutes: 30, seconds: 0, period: "AM" }}
  snapStep={5}
/>

In context

A five-minute scheduling control that keeps its wall-clock value explicit.

Focus session

10:30 AM

Choose a calm start time. The five-minute dial stays quick while the editable fields remain precise and familiar.

Props

RopeTimePicker accepts safe native div attributes and forwards its ref to the accessible root group. It intentionally does not parse dates, manage timezones, submit a hidden form value, or own a popover.

PropTypeDefaultDescription
valueRopeTimeValueControlled twelve-hour wall-clock value.
defaultValueRopeTimeValue12:00:00 AMInitial uncontrolled value.
onValueChange(value) => voidRuns once for every distinct snapped value requested by an interaction.
mode"hour" | "minute" | "second"Controlled unit being edited.
defaultMode"hour" | "minute" | "second""hour"Initial editing unit when mode is uncontrolled.
onModeChange(mode) => voidRuns when a field or control point requests another unit.
showSecondsbooleanfalseShows the seconds rope, slider, and digital field.
showDigitalbooleantrueShows the editable digital fields above the dial.
snapStep1 | 51Interaction step for minutes and seconds; hours always step by one.
size"sm" | "default" | "lg""default"Controls dial, center, dot, and readout scale.
motionIntensity"subtle" | "default" | "expressive""default"Controls endpoint settle, rope lag, and resting weight.
disabledbooleanfalseDisables every interaction and focus target.
readOnlybooleanfalseKeeps controls discoverable while preventing value changes.
classNamestringClass name applied to the root group.

Theming

Override these variables in your light and dark theme scopes. The registry installs the defaults automatically.

--suluu-rope-time-backgroundDial surface.
--suluu-rope-time-foregroundLabels, digits, and period text.
--suluu-rope-time-mutedMinute ticks and separators.
--suluu-rope-time-hourHour ticks and numerals.
--suluu-rope-time-borderDial and readout borders.
--suluu-rope-time-guideInner guide ring.
--suluu-rope-time-ropeInactive hour and minute rope color.
--suluu-rope-time-rope-highlightRope and control-point highlight.
--suluu-rope-time-accentActive hour and minute rope, point, and field.
--suluu-rope-time-secondSeconds rope and active second control.
--suluu-rope-time-controlInactive control-point surface.
--suluu-rope-time-control-borderControl and center borders.
--suluu-rope-time-centerAM/PM control surface.
--suluu-rope-time-center-hoverAM/PM hover surface.
--suluu-rope-time-readoutDigital readout surface.
--suluu-rope-time-readout-activeActive digital field wash.
--suluu-rope-time-readout-hoverInactive field hover wash.
--suluu-rope-time-ringKeyboard focus ring.
--suluu-rope-time-offsetColor behind focus-ring offsets.
--suluu-rope-time-shadowDial depth.
--suluu-rope-time-rope-shadowRope depth filter.
--suluu-rope-time-control-shadowControl-point elevation.
--suluu-rope-time-center-shadowAM/PM control elevation.
--suluu-rope-time-readout-shadowDigital readout elevation.

Sizes

Every size keeps the same SVG geometry and minimum control-point hit area; only its rendered scale and typography change.

The root exposes mode, size, disabled, read-only, and dragging state through data attributes. Individual ropes, fields, and points expose stable slot and mode attributes for local restyling.

Accessibility

Each visible control point is a named slider with live minimum, maximum, current value, and complete time text. Arrow keys move one allowed step and wrap naturally around the clock; Home and End move to the unit bounds. This follows the WAI-ARIA slider pattern.

The visible readout uses real text-editable spinbuttons, preserving native selection and editing while supporting arrows, direct numeric entry, Enter, and Escape. This also provides a reliable alternative to circular pointer gestures, following the WAI-ARIA spinbutton pattern.

Reduced motion removes spring lag and moves every rope immediately while retaining its quiet static curve. Disabled controls leave the tab order; read-only controls remain discoverable but cannot alter the time or period.

↑↓ to navigate↵ to openesc to close