@fictjs/shadcn
v0.3.0
Published
Official shadcn-style code distribution system for Fict
Downloads
270
Readme
@fictjs/shadcn
The official shadcn/ui-style code distribution system for Fict — a reactive UI library with compiler-driven fine-grained reactivity.
Instead of installing a component library as a dependency, @fictjs/shadcn copies beautifully-designed, accessible component source code directly into your project. You own the code, you customize it, and the CLI helps you keep it up to date.
Features
fictcnCLI — scaffold, add, remove, diff, update, and validate UI components from the terminal- 206 built-in registry entries — core Fict-native set plus expanded compatibility catalog
- Core Fict-native set — 35 UI components + 8 blocks + 5 themes
- Flexible registry source — use the bundled offline registry or a remote JSON registry
- Deterministic lock file —
fictcn.lock.jsontracks installed versions and SHA-256 file hashes for drift detection - Automatic dependency resolution — registry dependencies are resolved with circular dependency detection
- Tailwind CSS + CSS variables — baseline configuration generated for you, including PostCSS and
tailwindcss-animate - Package manager agnostic — auto-detects pnpm, npm, yarn, or bun
Install
pnpm add -D @fictjs/shadcn
# or
npm install -D @fictjs/shadcn
# or
yarn add -D @fictjs/shadcn
# or
bun add -D @fictjs/shadcnPrerequisites: Node.js 18+ and a Fict project. Tailwind baseline can be bootstrapped by
fictcn init.
If
@fictjs/shadcnis installed locally, run the CLI via your package manager:pnpm exec fictcn,npm exec fictcn,yarn fictcn, orbunx fictcn.
Quick Start
# 1. Initialize your project (generates config, globals.css, tailwind config, utilities)
pnpm fictcn init
# 2. Add components — dependencies are resolved automatically
pnpm fictcn add button dialog tabs table
# 3. Import and use in your Fict componentsimport { Button } from '@/components/ui/button'
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
function App() {
let count = $state(0)
return (
<Card>
<CardHeader>
<CardTitle>Counter</CardTitle>
</CardHeader>
<CardContent>
<Button onClick={() => count++}>Clicked {count} times</Button>
</CardContent>
</Card>
)
}CLI Reference
fictcn init
Scaffolds the project baseline: fictcn.json config, globals.css with design tokens, Tailwind config (e.g. tailwind.config.ts / tailwind.config.js / tailwind.config.mjs / tailwind.config.cjs), PostCSS config, and utility files (cn.ts, variants.ts). Installs required dependencies unless --skip-install is passed.
fictcn init [--skip-install] [--dry-run]fictcn add
Adds one or more components to your project from the configured registry (builtin or remote URL). Registry dependencies (e.g., dialog depends on button) are resolved and installed automatically.
fictcn add <components...> [--overwrite] [--skip-install] [--dry-run]
# Examples
fictcn add button
fictcn add dialog tabs accordion tooltip
fictcn add select --overwrite # replace existing filesfictcn blocks
Install pre-built UI blocks — higher-level compositions of multiple components.
fictcn blocks add <blocks...> [--overwrite] [--skip-install] [--dry-run]
fictcn blocks list
# Examples
fictcn blocks add auth/login-form dashboard/layoutfictcn theme
Apply color themes that override CSS custom properties with light/dark variants.
fictcn theme apply <themes...> [--overwrite] [--dry-run]
fictcn theme list
# Examples
fictcn theme apply theme-slatefictcn diff
Show a unified diff of local modifications against the configured registry source. Useful for reviewing what you've customized before updating.
fictcn diff [entries...]
# Examples
fictcn diff # diff all installed entries
fictcn diff button card # diff specific componentsfictcn update
Update installed registry entries from the configured registry source. Without --force, entries with local modifications are skipped.
fictcn update [entries...] [--force] [--skip-install] [--dry-run]
# Examples
fictcn update # update all
fictcn update button card # update specific entries
fictcn update --force # overwrite local changesfictcn remove / fictcn uninstall
Remove installed entries and tracked files from your project and lock file. By default, edited files are protected; pass --force to remove anyway.
fictcn remove <entries...> [--force] [--dry-run]
# Examples
fictcn remove button
fictcn remove auth/login-form theme-slate
fictcn remove button --forcefictcn doctor
Validate that your project is correctly configured: checks for fictcn.json, tsconfig.json alias paths, globals.css, your configured Tailwind file (tailwindConfig), and required npm dependencies.
fictcn doctorfictcn list
List all available registry entries.
fictcn list [--type components|blocks|themes|all] [--json] [--registry builtin|<url>]When --registry is omitted, the CLI uses fictcn.json (registry field) if available.
fictcn search
Search registry entries by keyword.
fictcn search <query> [--registry builtin|<url>]
# Examples
fictcn search dialog
fictcn search formConfiguration
Running fictcn init creates a fictcn.json at your project root:
{
"$schema": "https://fict.js.org/schemas/fictcn.schema.json",
"version": 1,
"style": "tailwind-css-vars",
"componentsDir": "src/components/ui",
"libDir": "src/lib",
"css": "src/styles/globals.css",
"tailwindConfig": "tailwind.config.ts",
"registry": "builtin",
"aliases": {
"base": "@",
},
}| Field | Description | Default |
| ---------------- | -------------------------------------------------------- | ------------------------ |
| componentsDir | Where UI component files are written | src/components/ui |
| libDir | Where utility files (cn.ts, variants.ts) are placed | src/lib |
| css | Path to the global CSS file with design tokens | src/styles/globals.css |
| tailwindConfig | Path to the Tailwind CSS configuration file | tailwind.config.ts |
| registry | Registry source (builtin, remote URL, or file:// URL) | builtin |
| aliases.base | TypeScript path alias prefix for imports | @ |
For remote registries, each entry in index.json (or registry.json) should include:
name, type, version, dependencies, registryDependencies, and files.
files supports two formats:
- Inline content:
[{ path, content }] - File reference:
[{ path }](the CLI fetches file contents relative to the registry JSON URL)
@fictjs/shadcn is compatible with shadcn-style registry type tags:
registry:ui,registry:block,registry:styleregistry:hook,registry:lib(treated as installable component entries)
Remote registry requests include:
- retry on transient failures (default
2retries) - request timeout (default
10000ms) - short-lived in-process cache (default
10000ms) - concurrent file fetches for file-reference registries (default
16)
Optional environment variables:
FICTCN_REGISTRY_RETRIESFICTCN_REGISTRY_TIMEOUT_MSFICTCN_REGISTRY_RETRY_DELAY_MSFICTCN_REGISTRY_CACHE_TTL_MSFICTCN_REGISTRY_FETCH_CONCURRENCY
Lock File
fictcn.lock.json is generated automatically and tracks every installed entry with:
- Version — the registry version at install time
- Timestamp — when the entry was installed
- File hashes — SHA-256 hashes of every generated file, enabling drift detection via
fictcn diff
Commit this file to version control so your team stays in sync.
Built-in Registry
The bundled registry now includes 206 entries in total:
- Core Fict-native entries: 35 components + 8 blocks + 5 themes
- Expanded Fict-native entries: 25 compatibility components + 132 blocks + 1 theme bootstrap template
Expanded entries are now generated as usable Fict templates (with meaningful imports, dependencies, and starter UI), rather than empty placeholder shells.
Core Components (35)
| Category | Components |
| ---------- | ---------------------------------------------------------------------------------------------------------- |
| Base | button, badge, card, separator, avatar, aspect-ratio, skeleton, label, input, textarea |
| Forms | checkbox, radio-group, switch, select, combobox, slider, toggle, toggle-group, form |
| Overlay | dialog, alert-dialog, popover, tooltip, hover-card, sheet |
| Navigation | dropdown-menu, context-menu, menubar, tabs, accordion, collapsible, navigation-menu |
| Feedback | toast, progress |
| Data | table |
Core Blocks (8)
| Block | Description |
| ------------------------ | ------------------------------------- |
| auth/login-form | Email/password login card |
| auth/signup-form | Account creation form |
| settings/profile | User profile settings page |
| dashboard/layout | Dashboard shell with header |
| dashboard/sidebar | Collapsible sidebar navigation |
| tables/users-table | Data table with user records |
| dialogs/confirm-delete | Destructive action confirmation modal |
| forms/validated-form | Form with field-level validation |
Core Themes (5)
| Theme | Description |
| ------------------- | ------------------------ |
| theme-default | Neutral gray palette |
| theme-slate | Cool slate tones |
| theme-zinc | Zinc/charcoal palette |
| theme-stone | Warm stone tones |
| theme-brand-ocean | Blue ocean brand palette |
All themes provide light and dark mode variants via CSS custom properties and can be applied with a class name (e.g., class="theme-slate dark").
Project Structure After Init
your-project/
├── fictcn.json # CLI configuration
├── fictcn.lock.json # Deterministic lock file
├── tailwind.config.ts # Auto-configured with design tokens
├── postcss.config.mjs # PostCSS with Tailwind + Autoprefixer
└── src/
├── components/
│ └── ui/
│ ├── button.tsx # ← added by `fictcn add button`
│ ├── card.tsx
│ └── ...
├── lib/
│ ├── cn.ts # clsx + tailwind-merge utility
│ └── variants.ts # class-variance-authority re-export
└── styles/
└── globals.css # Tailwind directives + design tokensHow It Works
fictcn initdetects your project root, package manager, and TypeScript config. It generates baseline files and installs core dependencies (@fictjs/ui-primitives,class-variance-authority,clsx,tailwind-merge).fictcn add buttonlooks upbuttonin your configured registry, resolves any registry dependencies (e.g., addingdialogalso pulls inbutton), renders template files with your configured paths and aliases, writes them tocomponentsDir, and records everything in the lock file with SHA-256 hashes.You own the code. Modify the generated components however you like. When the registry updates, use
fictcn diffto see what changed, andfictcn updateto pull in upstream improvements — your local changes are preserved unless you pass--force.fictcn doctorvalidates the full setup: config file, TypeScript aliases, CSS tokens, Tailwind config, and npm dependencies — catching misconfigurations early.
Programmatic API
All CLI commands are also available as TypeScript functions:
import { runInit, runAdd, runRemove, runDiff, runDoctor, runList } from '@fictjs/shadcn'
// Initialize programmatically
await runInit({ skipInstall: true })
// Add components
await runAdd({ components: ['button', 'dialog'], overwrite: false })
// Remove entries
await runRemove({ entries: ['dialog'] })
// Check for drift
const { patches } = await runDiff()
// Validate project health
const { ok, issues } = await runDoctor()
// List registry entries
const output = runList({ type: 'components', json: true })Storybook
This repo includes a Fict-native Storybook setup for developing and previewing components:
pnpm storybook # start dev server on port 6006
pnpm storybook:build # build static site
pnpm storybook:smoke # CI smoke testDevelopment
# Install dependencies
pnpm install --ignore-workspace
# Development
pnpm dev # watch mode
pnpm build # production build
# Quality
pnpm lint # ESLint
pnpm typecheck # TypeScript validation
pnpm test # run all tests
pnpm test:watch # watch modeJSON Schemas
Schemas for editor autocompletion and validation:
- Config:
https://fict.js.org/schemas/fictcn.schema.json - Lock file:
https://fict.js.org/schemas/fictcn-lock.schema.json
Local copies are in the schemas/ directory.
License
MIT © Fict
