@saasflare/ui
v3.7.0
Published
The Next.js UI library — App Router-aware Radix primitives with Tailwind v4 and Motion, animated by default.
Maintainers
Readme
@saasflare/ui
The Saasflare design system — an opinionated, themeable React component library
for Next.js 16 + Tailwind CSS v4, animated by default. Every component is
motion-aware, powered by Framer Motion and LazyMotion for a tight ~25 KB
runtime overhead.
npm install @saasflare/ui
# or
pnpm add @saasflare/ui
# or
yarn add @saasflare/ui- Repo: https://github.com/saasflare/saasflare-ui
- Catalog: https://ui.saasflare.io
- Demo: https://demo.saasflare.io
- License: MIT
Highlights
- 80+ components — primitives (Button, Dialog, Form, Select, …) and composed widgets (PricingCard, FeatureCard, MetricCard, BentoGrid, …).
- Animated by default — every interactive primitive ships with motion via
Framer Motion +
LazyMotion features={domAnimation}(~25 KB gzip total). - Tailwind v4 native — tokens declared via
@theme, notailwind.config.tsextension required. - Theming via CSS variables — switch palettes by setting
data-palette="…"on<html>. 20 presets shipped, custom palettes are one CSS block. - Light / dark out of the box — driven by
next-themes. - TypeScript strict — full types, no
any. - AI-codegen friendly — shadcn-compatible registry (
npx shadcn add https://ui.saasflare.io/r/<name>.json) lets AI tools (v0, Lovable, Bolt, Cursor, Claude) pull component source straight into your project.llms.txtandllms-full.txtpublished for LLM discovery.
For AI codegen tools
This library publishes three artifacts AI generators can consume:
| URL | Purpose |
|---|---|
| https://ui.saasflare.io/llms.txt | Concise index (per llmstxt.org) |
| https://ui.saasflare.io/llms-full.txt | Full component reference — props, types, examples |
| https://ui.saasflare.io/registry.json | shadcn-compatible registry index — list of every installable component |
| https://ui.saasflare.io/api/mcp | Remote MCP server — let Claude / Cursor / Claude Code query the catalog live (see "MCP server" below) |
MCP server
Add the endpoint URL to any MCP-aware client and your agent can call list_components, get_component, search_components, recommend_for_use_case, get_install_command, list_palettes, get_palette, and list_hooks directly.
Claude Code
claude mcp add --transport http saasflare-ui https://ui.saasflare.io/api/mcpClaude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)
{
"mcpServers": {
"saasflare-ui": { "url": "https://ui.saasflare.io/api/mcp" }
}
}Cursor (.cursor/mcp.json)
{
"mcpServers": {
"saasflare-ui": { "url": "https://ui.saasflare.io/api/mcp" }
}
}To pull a component's source into a project (the AI-friendly path):
pnpm add @saasflare/ui # runtime, providers, motion bundle
npx shadcn add https://ui.saasflare.io/r/feature-card.json # source of one component
npx shadcn add https://ui.saasflare.io/r/pricing-card.json # …and anotherThe imported files land in your project's components/ui/ (or wherever your components.json aliases point) with all internal imports already rewritten to @saasflare/ui. No further wiring needed.
To regenerate locally:
pnpm --filter @saasflare/ui build:registry # writes apps/ui/public/r/*.json
pnpm --filter @saasflare/ui build:llms # writes apps/ui/public/llms{,-full}.txtTo add a new component to the registry, append an entry to packages/ui/registry.json and rebuild.
Peer dependencies
@saasflare/ui is a Next.js-first library. The required peers reflect actual
runtime coupling — there is no graceful degradation if they are missing.
Required
pnpm add react react-dom next next-themes framer-motion| Peer | Range | Notes |
| --------------- | --------------------------- | ---------------------------------------- |
| react | ^18.2.0 \|\| ^19.0.0 | |
| react-dom | ^18.2.0 \|\| ^19.0.0 | |
| next | ^16.0.0 | Next 16 only — buyers on 15 upgrade first |
| next-themes | ^0.4.0 | Light/dark mode driver |
| framer-motion | ^12.0.0 | Used eagerly by core primitives |
tailwindcss is not a peer dependency — it's a build-time tool. Install it
in your app and add a @source directive (see Setup below).
Required by main-barrel components
Form (react-hook-form) and DatePicker/DateRangePicker
(react-day-picker, pulled in via Calendar) live in the main barrel, and
the current bundled dist imports those peers eagerly — importing anything
from @saasflare/ui resolves them. They are therefore declared as required
peers (no peerDependenciesMeta.optional) until the per-module dist lands:
| Peer | Used by |
| ------------------ | -------------------------------------------------------- |
| react-hook-form@^7 | Form family |
| react-day-picker@^9 | DatePicker, DateRangePicker |
@hookform/resolvers@^5 and zod@^4 stay optional — install them only for
schema-validated forms.
Toasts (regular dependency — no separate install)
Toaster wraps sonner, which ships as a
regular dependency of @saasflare/ui — your package manager installs it
automatically. Import the imperative API from the barrel so your app and the
mounted <Toaster /> are guaranteed to share one sonner instance:
import { Toaster, toast } from "@saasflare/ui"Subpath imports (heavy, low-frequency, or non-tree-shakeable peers)
These components are not in the main barrel — import them via their subpath. This keeps the peer (and its side-effects, e.g. CSS injection) out of consumers who don't use the component.
| Subpath | Install | Notes |
| -------------------------- | ---------------------------------------- | ---------------------------------------- |
| @saasflare/ui/chart | recharts@^3 | ~95 KB gzip peer |
| @saasflare/ui/carousel | embla-carousel-react@^8 | ~25 KB peer |
| @saasflare/ui/calendar | react-day-picker@^9, date-fns@^4 | ~30 KB peer combined |
| @saasflare/ui/drawer | vaul@^1 | Mobile drawer / bottom sheet |
| @saasflare/ui/command | (no extra install — cmdk bundled) | Full Command palette / cmdk-based modal |
| @saasflare/ui/input-otp | input-otp@^1 | OTP / 2FA input |
| @saasflare/ui/resizable | react-resizable-panels@^4 | Split-view panels |
Setup
1. Import the styles bundle and configure Tailwind
/* app/globals.css */
@import "@saasflare/ui/styles";
@source "../node_modules/@saasflare/ui/dist/**/*.{js,mjs}";The @source directive tells Tailwind v4's JIT engine to scan the package's
compiled output for utility classes (otherwise they get purged). The @import
"@saasflare/ui/styles" line pulls in the @theme token block, palette presets,
light/dark surface variables, and motion tokens.
Tailwind v3 users: add the dist path to
contentintailwind.config.{js,ts}:content: ["./node_modules/@saasflare/ui/dist/**/*.{js,mjs}", /* ... */]
2. Make SaasflareShell your document root (mandatory)
SaasflareShell is the document — it renders <html> and <body>
itself, plus the design-system context inside. Do not wrap it in your
own <html>/<body> tags; replace them entirely.
// app/layout.tsx
import { SaasflareShell } from "@saasflare/ui";
import { fontVariables } from "@saasflare/ui/fonts/default";
import "./globals.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<SaasflareShell
lang="en"
palette="saasflare"
theme="dark"
className={fontVariables}
>
{children}
</SaasflareShell>
);
}SaasflareShell accepts palette, theme, surface, radius,
animated, smoothScrolling, storageKey, plus a lang, className
(applied to <html>), bodyClassName, and a head slot for <head>
content. The chosen palette/surface/radius/animated props are
baked into the SSR HTML as data-* attributes, so there is zero FOUT
and the pre-hydration script is disabled by default.
⚠️ Required, not optional.
@saasflare/uiusesLazyMotion features={domAnimation} strictto keep the motion bundle tight. Animated components use them.*API (e.g.m.button) which throws at runtime ifLazyMotionis missing.SaasflareShell(orSaasflareProviderdirectly, when you need to own<html>/<body>yourself) provides it. Without one, everyButton,Card,Dialog, etc. will error on mount.
When to use SaasflareProvider instead: if you need a runtime palette
switcher (user picks a palette via a toggle, persisted in localStorage),
keep your own <html>/<body> and wrap children in SaasflareProvider.
The provider's pre-hydration script reads localStorage before paint.
SaasflareShell is for brand-locked apps where the palette is decided at
SSR time.
3. Use components
import { Button, Card, CardHeader, CardTitle, CardContent } from "@saasflare/ui";
export function Example() {
return (
<Card>
<CardHeader>
<CardTitle>Hello Saasflare</CardTitle>
</CardHeader>
<CardContent>
<Button>Get started</Button>
</CardContent>
</Card>
);
}Components with heavy or low-frequency peers ship as subpaths:
import { ChartContainer, ChartTooltip } from "@saasflare/ui/chart";
import { Carousel, CarouselContent, CarouselItem } from "@saasflare/ui/carousel";
import { Calendar } from "@saasflare/ui/calendar";
import { Drawer, DrawerContent, DrawerTrigger } from "@saasflare/ui/drawer";
import { Command, CommandInput, CommandList } from "@saasflare/ui/command";
import { InputOTP, InputOTPGroup, InputOTPSlot } from "@saasflare/ui/input-otp";
import { ResizablePanel, ResizablePanelGroup } from "@saasflare/ui/resizable";Theming
Switch palette at runtime
<html data-palette="ocean">Built-in presets: saasflare (default), ocean, ink, aurora, indigo,
emerald, violet, coral, stone, jade, cobalt, amber, fuchsia,
honey, teal, iris, ruby, colorful, craivo.
colorful is special: switching to it auto-applies a soft pastel gradient
on hover (peach → blush → lavender → cyan) wrapped in a matching
color-aura glow, to all outline buttons, feature/testimonial/team/spotlight
cards, and feature-card icon chips on the page. Cards get a gradient
border ring; buttons fill with the pastel sweep. No component-side opt-in.
Define a custom palette
Add a block to your global CSS:
:root[data-palette="brand"] {
--primary-h: 220;
--primary-c: 0.18;
--primary-l: 55%;
/* see packages/ui/styles/palettes.css for the full token list */
}Light / dark
SaasflareShell integrates with next-themes. Drop in the ThemeModeToggle
component or call useSaasflareTheme() for a programmatic API.
Fonts
Six curated presets ship with the package. Pick one or roll your own:
import { fontVariables } from "@saasflare/ui/fonts/default";
// or: "@saasflare/ui/fonts/editorial"
// "@saasflare/ui/fonts/geometric"
// "@saasflare/ui/fonts/rounded"
// "@saasflare/ui/fonts/distinctive"
// "@saasflare/ui/fonts/neutral"Apply fontVariables to <html> or <body> — the CSS variables defined by
the design system pick them up automatically.
Subpath exports
| Path | What it is |
| --------------------------------- | ------------------------------------------------------------------- |
| @saasflare/ui | Core: components, hooks, providers, utilities (incl. Form, Toaster) |
| @saasflare/ui/calendar | Calendar (requires react-day-picker, date-fns) |
| @saasflare/ui/carousel | Carousel (requires embla-carousel-react) |
| @saasflare/ui/chart | Chart primitives (requires recharts) |
| @saasflare/ui/command | Command palette / cmdk modal |
| @saasflare/ui/drawer | Mobile drawer (requires vaul) |
| @saasflare/ui/input-otp | OTP input (requires input-otp) |
| @saasflare/ui/resizable | Resizable panels (requires react-resizable-panels) |
| @saasflare/ui/styles | Full CSS bundle (alias for globals.css) |
| @saasflare/ui/globals.css | Same as above, explicit |
| @saasflare/ui/theme.css | Token root only (advanced use) |
| @saasflare/ui/fonts | Font preset registry |
| @saasflare/ui/fonts/{preset} | default, editorial, geometric, rounded, distinctive, neutral |
What's exported from the main entry
- Utilities:
cn - Hooks:
useIsMobile,useReducedMotion,useDisclosure,useMeasure,usePagination - Providers:
SaasflareShell,SaasflareProvider,SaasflareScript,SmoothScrollProvider,useSaasflareTheme,useSaasflareProps,useAnimation - Type tokens:
PALETTES,STYLES,RADII, plus matching TS types (PaletteId,StyleVariant,Palette,Surface,Radius,Size,Density, …) - Composed widgets:
ScrollToTopButton,ThemeModeToggle,TopLoadingBar,UserAvatar - All core UI primitives from
components/ui(Calendar, Carousel, Chart, Command, Drawer, InputOTP, and Resizable are not here — see Subpath imports above) — full list and live examples in the catalog.
Versioning
Semantic versioning. Breaking changes to component props, theme tokens, or palette names ship as major bumps. Release notes live on GitHub Releases.
License
MIT © Saasflare
