text ─────────────────────────────────────── F L U I D F U N C T I O N A L I S M ─────────────────────────────────────── Fluid Functionalis…
text ─────────────────────────────────────── F L U I D F U N C T I O N A L I S M ─────────────────────────────────────── Fluid Functionalis…
───────────────────────────────────────
F L U I D F U N C T I O N A L I S M
───────────────────────────────────────
Refined UI components with satisfying hover.
A shadcn/ui registry of components, the systems they share, and blocks that compose them. Every transition exists to make a state change legible: springs instead of durations, one hover highlight that glides to the item nearest your cursor, and labels that get heavier without shifting the layout. Components that touch a primitive ship in two flavors, Radix and Base UI, with the same API on both.
Docs and demos · Browse components · Compare with shadcn/ui
Add the registry to your project once:
npx shadcn@latest registry add @fluid
Then install any component, system, or block by its registry name:
npx shadcn@latest add @fluid/button
Or install straight from the URL, without adding the registry:
npx shadcn@latest add https://www.fluidfunctionalism.com/r/button.json
Dependencies, shared libs, and hooks resolve on their own.
Every component that touches a primitive has both a Radix and a Base UI flavor. The bare name installs Radix. Put base/ in front of it for Base UI:
npx shadcn@latest add @fluid/base/button
The URL form is https://www.fluidfunctionalism.com/r/base/button.json. Dependencies follow the flavor you pick, so a Base UI dialog pulls in the Base UI button. Components built on top of a flavored one (AskUserQuestions, ColorPicker, CommandMenu, InputCopy, InputMessage, and the blocks) accept base/ too. Everything else has one source and installs from the bare name in either kind of project. The tables below list the names.
A stock shadcn project already has button.tsx, dialog.tsx, tooltip.tsx, and friends. This library installs under the same names, so pass --overwrite to replace them:
npx shadcn@latest add @fluid/dialog --overwrite
Without the flag the CLI asks per existing file, and a non-interactive shell (a coding agent, a CI job) exits at the first question.
Font weight animations use Inter's wght and opsz axes together: the heavier weight widens a label, a tighter optical size pulls it back, so text changes weight without moving its neighbours. Load the variable font with both axes.
Self-hosted, the way the docs site does it:
@font-face {
font-family: "Inter";
src: url("/fonts/InterVariable.ttf") format("truetype");
font-weight: 100 900;
font-display: swap;
}
With next/font/google, ask for the axis: Inter({ subsets: ["latin"], axes: ["opsz"] }).
Every doc page and playground has a Copy prompt button. The prompt is a self-contained brief: the install command, a usage snippet, the props, and the docs URL. Paste it into your agent and it wires the component in without fetching anything.
Install with npx shadcn@latest add @fluid/. A second name means the component has a Base UI flavor.
| Component | Registry name | What it does |
|---|---|---|
| Accordion | accordion · base/accordion |
Collapsible sections with animated expand/collapse and fluid hover in grouped mode |
| AskUserQuestions | ask-user-questions · base/ask-user-questions |
Stepped question flow with single/multi-select, an inline "other" input, skip, and multi-question navigation |
| Badge | badge |
Compact label with solid and dot variants, the Tailwind color palette, and 2 sizes |
| Button | button · base/button |
Variants, sizes, loading state, icon slots, and a weight shift on hover |
| Card | card |
shadcn's compositional card with stacked, inline, and grid layouts, borderless dividers, media/logo/feature slots, and 2-D fluid hover |
| ChatMessage | chat-message |
Chat transcript bubble with baked-in motion, user/assistant alignment, and file attachments |
| CheckboxGroup | checkbox-group · base/checkbox-group |
Checkbox group with merged backgrounds for contiguous selections |
| ColorPicker | color-picker · base/color-picker |
HEX, RGB, HSL, and OKLCH formats with alpha, swatches, and eyedropper, inline or in a popover |
| Combobox | combobox · base/combobox |
Type-to-filter field with keyboard highlight, fluid hover, chips for multiple selection, and a create-from-query row |
| CommandMenu | command-menu · base/command-menu |
Type to filter a list of actions, arrow through them, press Enter: groups, shortcut caps, suggestions, and a dialog shell on ⌘K |
| Dialog | dialog · base/dialog |
Modal with spring enter/exit and overlay in 3 widths, the largest a canvas for a sidebar |
| Dropdown | dropdown · base/dropdown |
Menu-style dropdown with fluid hover, animated selection, and an optional search field in the popup |
| InputCopy | input-copy · base/input-copy |
Read-only input with copy-to-clipboard and animated feedback |
| InputGroup | input-group |
Input fields with fluid hover, animated labels, and validation |
| InputMessage | input-message · base/input-message |
Chat-style composer with auto-resizing textarea, file drop, action slots, and a built-in send button |
| RadioGroup | radio-group · base/radio-group |
Radio buttons with fluid hover and animated selection |
| Select | select · base/select |
Animated select with bordered/borderless variants, typeahead, and optional icons |
| Sidebar | sidebar · base/sidebar |
Composable app sidebar: drag its edge to resize, collapse it away or press [ or ], and a drawer on mobile |
| Slider | slider · base/slider |
Spring-snapped thumb, step dots, range mode, and a click-to-edit value |
| Switch | switch · base/switch |
Toggle with animated thumb and label |
| Table | table |
Data table with fluid hover on rows and semantic markup |
| Tabs | tabs · base/tabs |
Segmented control with sliding indicator and fluid hover |
| TabsSubtle | tabs-subtle · base/tabs-subtle |
Tab navigation with an animated pill indicator |
| ThinkingIndicator | thinking-indicator |
Animated status indicator with morphing SVG and cycling text |
| ThinkingSteps | thinking-steps · base/thinking-steps |
Chain-of-thought display with sequential animation and collapsible steps |
| Tooltip | tooltip · base/tooltip |
Spring-based floating tooltip with configurable placement |
The systems every component shares. Each installs as code, the same way.
| System | Registry name | What it does |
|---|---|---|
| Fluid Hover | use-fluid-hover |
One hook and one highlight per list. The highlight glides to the item nearest your cursor and never blinks off between rows |
| Motion | springs |
3 spring speeds, fast, moderate, and slow, each with an exit one tier quicker than its entrance |
| Scrollbars | scroll-area · base/scroll-area |
A scrollbar that stays out of the way but never disappears, with native scroll on touch |
| Sizes | size-context |
2 sizes, a 36px default and a 28px compact, shared by buttons, inputs, selects, tabs, and rows |
| Surfaces | elevated |
8 elevation levels so popovers, dropdowns, and dialogs stay visible at any depth, in light and dark |
Compositions that install as one item each, with every component they use.
| Block | Registry name | What it is |
|---|---|---|
| App Sidebar | sidebar-app · base/sidebar-app |
A complete app shell: workspace header, search field, collapsible sections with badges, user footer, and an inset topbar |
| Settings Dialog | dialog-sidebar · base/dialog-sidebar |
The xl Dialog as a canvas, a Sidebar of sections down its left edge, and a scrolling panel of controls |
| Queued message stack | queued-stack · base/queued-stack |
Sonner-style stack of queued composer messages: fan out on hover, drag to reorder, morph into the sent message |
The Sidebar, Card, InputMessage, AskUserQuestions, Dropdown, Combobox, and CommandMenu playgrounds encode the configuration you build in the rail into a short code. Nothing is stored: the code is the configuration itself. Install it as one block that composes the component with the options you picked:
npx shadcn@latest add https://www.fluidfunctionalism.com/r/preset/.json
Add ?preset= to the doc page URL to reopen the playground as you left it, or to share it.
Components render icons through named slots with Lucide defaults, so lucide-react is the only icon dependency an install adds. To use another icon library, wrap your app in the installed IconProvider and override any slot. Names you leave out keep their Lucide default:
import { IconProvider } from "@/lib/icon-context";
import { CaretRight, MagnifyingGlass } from "@phosphor-icons/react";
The icon-library switcher on the docs site is a preview tool only. None of that machinery ships with installed components.
No open issues yet, or sync has not completed.