Blob Selector
NewCustomize
Medium
Stretch0.60
Thin0.50
Color
Active text
Installation
npx shadcn@latest add https://uibrik.com/r/blob-selector.jsonInstall the packages
npm install motionAdd the cn helper
Imports
cnfrom@/lib/utils, whichshadcn initcreates. Add it by hand without shadcn.Copy the source into your project
components/uibrik/blob-selector/blob-selector.tsx"use client"; import { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent, type PointerEvent, type ReactNode } from "react"; import { animate, motion, useMotionValue, useReducedMotion, useTransform } from "motion/react"; import { cn } from "@/lib/utils"; // Segmented control with a liquid pill. The pill's two edges spring // separately: the leading edge snaps toward the new segment and the trailing // edge lags behind, so the pill stretches across and then gathers itself up. // While it's stretched it thins out, as if keeping its volume, and fills back // out as it settles. Pressing squeezes it; pressing and dragging scrubs the // liquid across the segments, and the choice is made on release. // // Labels never move or scale. A second copy of the row in the selected // colours sits on top, clipped to the pill's shape, so the text changes colour // exactly where the liquid covers it. // // It's a radio group: Tab lands on the selected segment, arrows move the // choice, Home and End jump to the ends. export type BlobOption = string | { value: string; label: ReactNode; icon?: ReactNode; disabled?: boolean }; export type BlobSelectorProps = { options: readonly BlobOption[];
Adds the files to
components/uibrik/blob-selector and installs motion. With the @uibrik namespace set up: npx shadcn@latest add @uibrik/blob-selector.Usage
import { BlobSelector } from "@/components/uibrik/blob-selector/blob-selector";<BlobSelector options={["Day", "Week", "Month", "Year"]} size="md" stretch={0.6} thin={0.5} draggable equalWidth={false} color="" activeColor="" defaultValue="Week" label="Range" // value="…" // onChange={(value) => {}}/>Props
BlobSelector- size
- Type "sm" | "md" | "lg"
- "md"
- Height and text size.
- stretch
- Type number
- 0.6
- How far the trailing edge lags behind; 0 slides a rigid pill.
- thin
- Type number
- 0.5
- How much the pill thins while it's stretched.
- draggable
- Type boolean
- true
- Press and drag across the segments to scrub; the choice is made on release.
- equalWidth
- Type boolean
- false
- Give every segment the width of the widest one.
- color
- Type string
- ""
- Pill colour; empty uses the foreground colour.
- activeColor
- Type string
- ""
- Text colour on the pill; empty uses the background colour.
- optionsrequired
- Type (string | { value; label; icon?; disabled? })[]
- –
- Segments in order.
- value / onChange
- Type string / (value) => void
- –
- Controlled selection.
- defaultValue
- Type string
- –
- Selection on mount when uncontrolled. Defaults to the first option.
- label
- Type string
- –
- Names the group for screen readers.
- className
- Type string
- –
- Classes for the bar.