Components
Mood slider
A satisfaction rating as a face that changes with the slider: the mouth bends from a frown to a smile, the eyes soften and the colour warms from red through amber to green, with the word for each step beneath.
pnpm dlx shadcn@latest add @caliper/mood-sliderWhen to use
Use it for
- Satisfaction and effort surveys after support, onboarding or a purchase.
- Check-ins where a friendly control gets more answers.
Skip it when
- Precise ratings; use `Rating` or a number scale.
- Serious or sensitive contexts where a cartoon face is out of place.
Decisions
Why it is built this way, so you know what to keep when you change your copy.
Behaviour
- Continuous, then a step
- Dragging bends the face smoothly and lets go on the nearest step; arrow keys move one step.
Styling
- Face and word agree
- Shape, colour and the word all say the same thing, so it reads without colour.
Usage
- A native range
- It is a range input with each step's word as its value text.
Installation
pnpm dlx shadcn@latest add @caliper/mood-slider
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage
This is the code behind the preview above.
import { useState, type ReactNode } from "react" import { Badge } from "@/components/ui/badge" import { MoodSlider } from "@/components/ui/mood-slider" function Panel({ title, context, className = "max-w-md", children }: { title: string; context: string; className?: string; children: ReactNode }) { return ( <section className={`grid w-full gap-5 rounded-overlay border border-border bg-background p-6 shadow-resting max-sm:p-4 ${className}`}> <div className="grid gap-1"> <p className="font-medium">{title}</p> <p className="text-sm text-muted-foreground">{context}</p> </div> {children} </section> ); } export function MoodSliderDemo() { const [mood, setMood] = useState(3); return ( <Panel title="Quick check-in" context="Drag the slider or use the arrow keys." className="max-w-sm"> <MoodSlider label="How was your onboarding?" value={mood} onValueChange={setMood} /> <Badge className="justify-self-center">Saved: {["Awful", "Poor", "Okay", "Good", "Great"][mood]}</Badge> </Panel> ); }
API reference
MoodSlider
component
Also accepts the native props of its root element and a ref.
Accessibility
It is built on native elements and keeps aria-hidden and aria-valuetext in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.
Related
- RatingStars that are a native radio group: arrows change the value, a pointer previews, half steps when you need them, and a read-only average that says how many ratings it comes from.
- PollA question with a few answers. Before voting the answers are a plain list of buttons; choosing one reveals the results, each bar growing to its share, your vote ticked and the leader in bold, with Change vote to take it back.
- Feedback widgetA small widget to rate and comment from any page.