AI skill for manual setup
Prefer to let an AI agent handle the steps below? Copy this skill into your assistant (Claude Code, Cursor, and similar) and it will configure your React project to use the compositions.
Manual setup
If your project is not using shadcn/ui, compositions need a few small pieces that shadcn/ui would normally provide: a couple of utility packages, a cn() helper, the design-token CSS variables, and the @ import alias. This guide adds all four. It takes only a couple of minutes and you only do it once.
Before you start: this guide assumes an existing React + Tailwind CSS v4 + TypeScript project. It adds only the shadcn/ui pieces compositions rely on, not React, Tailwind, or TypeScript themselves.
1. Install the dependencies
Compositions animate with Motion, draw their icons from lucide-react, and merge class names with clsx + tailwind-merge:
npm install motion lucide-react tailwind-merge clsx
If your project already uses a different icon library, you still need lucide-react for the icons inside the compositions. It can live alongside your existing icon set.
2. Add the cn() helper
Compositions compose Tailwind classes through a cn() helper. Create lib/utils.ts with:
import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
3. Add the design-token CSS variables
Compositions color their brand surfaces with shadcn/ui semantic tokens (--primary, --card, --muted, --border, and friends). Paste the default token set into your global stylesheet, the same file where you import Tailwind. This is the standard shadcn/ui neutral theme, so you can recolor later by editing these values.
:root { --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); --popover-foreground: oklch(0.145 0 0); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); --muted-foreground: oklch(0.556 0 0); --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); --chart-1: oklch(0.87 0 0); --chart-2: oklch(0.556 0 0); --chart-3: oklch(0.439 0 0); --chart-4: oklch(0.371 0 0); --chart-5: oklch(0.269 0 0); --radius: 0.625rem; --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); } .dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.87 0 0); --chart-2: oklch(0.556 0 0); --chart-3: oklch(0.439 0 0); --chart-4: oklch(0.371 0 0); --chart-5: oklch(0.269 0 0); --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.556 0 0); }
Then expose those variables to Tailwind so utilities like bg-card and text-muted-foreground resolve. In your Tailwind entry CSS, map each token to a color:
@theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); }
Make sure dark mode is wired to the .dark class with..
@custom-variant dark (&:is(.dark *));
..so the dark tokens apply when .dark is on your html element.
4. Configure the @ import alias
Compositions import the cn() helper as @/lib/utils, and you import each composition as @/components/codedvisuals/<category>/<name> (for example @/components/codedvisuals/charts/bar). The @ is an alias that points to your source root (the folder that holds lib and components). Most projects are already configured with this alias, so you can skip this step. If you need to configure it, do it once and both kinds of import resolve without per-file edits.
Copy composition files into components/codedvisuals/<category>/ at that source root, mirroring the library structure, so their @/components/codedvisuals/... imports line up:
src/
components/
codedvisuals/
charts/
bar.tsx
The alias is set in two places: your TypeScript config (for editor and type checking) and your bundler (for the actual build).
In tsconfig.json, map @/* to your source folder:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } }
Then mirror the same alias in your bundler. For Vite:
import { defineConfig } from "vite"; import path from "node:path"; export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, });
Point both aliases at whichever folder is your source root. If your project keeps code in
src/, use./src. In other setups the root may differ (for example a Laravel app maps@/*to./resources/js/*).
You are set
With the dependencies, the cn() helper, the token variables, and the @ alias in place, every composition in the library works exactly as it does on a shadcn/ui project. Continue to Usage to start customizing.