Glass Switch
lore-glass/glass-switchFreeComponent
An iOS-style liquid-glass switch: the thumb rests as an opaque platter and lifts into a clear warping lens on press, with velocity-driven gel deformation, rubber-band overdrag, and overshoot travel tweens.
Live preview
live · rendered by the registry
Rendered by lore-glass on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://loreglasses.com/r/glass-switch.jsonSource
1"use client";23import { Glass, useGlassDark } from "@/components/ui/glass";4import {5 glassEase,6 MotionValue,7 PRESS_DURATION,8 prefersReducedMotion,9 RELEASE_DURATION,10 rubberBand,11 SpringDriver,12 TRAVEL_DURATION,13 tween,14} from "@/components/ui/glass-motion";15import { cn } from "@/lib/utils";16import { useCallback, useEffect, useRef, useState } from "react";1718const TRACK_W = 74;19const TRACK_H = 28;20const THUMB_W = Math.round(0.6 * TRACK_W);21const THUMB_H = TRACK_H - 6;22const INSET = 3;23const TRAVEL = TRACK_W - THUMB_W - 6;24const TRACK_R = TRACK_H / 2;25const LENS_HALF_W = THUMB_W / 2;26const LENS_HALF_H = THUMB_H / 2;27const LENS_R = THUMB_H / 2;28const FILL_H = Math.round(0.75 * TRACK_H);29const RUBBER_OVERSHOOT = TRACK_W * 0.1;30const RUBBER_DAMPENING = 30;31const BLEED =32 Math.ceil(0.5 * Math.max(LENS_HALF_W, LENS_HALF_H) + RUBBER_OVERSHOOT) + 2;33const HOLD_MS = 200;34const DRAG_THRESHOLD = 3;35const TAP_COLLAPSE_MS = 330;36const PRESS_GROW = 1.5;37const TINT_BLUR = 4;38const REST_TINT = 1;39const DEFORM_STIFFNESS = 180;40const DEFORM_DAMPING = 14;41const DEFORM_CAP = 0.35;42const DEFORM_GAIN = 0.012;43const DEFORM_EXP = 0.75;44const HOLD_BOOST = 0.175;4546const PRIMARY = "#0a84ff";47const BG4_LIGHT = "#e1dfdf";48const BG4_DARK = "#2a2828";4950interface GlassSwitchProps {51 ariaLabel?: string;52 checked?: boolean;53 className?: string;54 defaultChecked?: boolean;55 disabled?: boolean;56 name?: string;57 onCheckedChange?: (checked: boolean) => void;58 value?: string;59}6061function GlassSwitch({62 checked,63 defaultChecked = false,64 onCheckedChange,65 disabled = false,66 name,67 value,68 ariaLabel,69 className,70}: GlassSwitchProps) {71 const dark = useGlassDark();72 const [internal, setInternal] = useState(defaultChecked);73 const isOn = checked ?? internal;74 const isOnRef = useRef(isOn);75 isOnRef.current = isOn;7677 const markerRef = useRef<HTMLDivElement | null>(null);78 const hitRef = useRef<HTMLDivElement | null>(null);79 const trackRef = useRef<HTMLDivElement | null>(null);80 const fillRef = useRef<HTMLDivElement | null>(null);81 const brightnessRef = useRef<HTMLDivElement | null>(null);82 const tintRef = useRef<HTMLDivElement | null>(null);83 const shadowRef = useRef<HTMLDivElement | null>(null);84 const inputRef = useRef<HTMLInputElement | null>(null);8586 const x = useRef(new MotionValue(isOn ? TRAVEL : 0));87 const lensHalfW = useRef(new MotionValue(LENS_HALF_W));88 const lensHalfH = useRef(new MotionValue(LENS_HALF_H));89// … truncated
What it pulls in
Other registry items
Files it writes
More from lore-glass
All 10 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Glassglass | lore-glass | Components | Free | no deps · 4 files | |
| Glass Buttonglass-button | lore-glass | Components | Free | no deps | |
| Glass Dialogglass-dialog | lore-glass | Components | Free | 1 dep | |
| Glass Dockglass-dock | lore-glass | Components | Free | 1 dep | |
| Glass Inputglass-input | lore-glass | Components | Free | 1 dep | |
| Glass Popoverglass-popover | lore-glass | Components | Free | 1 dep | |
| Glass Sliderglass-slider | lore-glass | Components | Free | no deps | |
| Glass Tabsglass-tabs | lore-glass | Components | Free | 1 dep |
