Docs
Manual Installation

Manual Installation

Add dependencies to your project manually.

Manual

CSS framework

Components are styled using Tailwind CSS and Uno CSS. You need to install Tailwind CSS or Uno CSS in your project.

Follow the Tailwind or Uno installation instructions to get started.

Add dependencies

Add the following dependencies to your project if your are using tailwind:

npm install tailwindcss-animate class-variance-authority clsx tailwind-merge

or uno:

npm install unocss-preset-animations class-variance-authority clsx tailwind-merge

Path Aliases

I’m use the @ alias to make it easier to import your components. This is how you can configure it:

tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
app.config.ts
import { defineConfig } from "@solidjs/start/config";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
 
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
 
export default defineConfig({
  vite: {
    resolve: {
      alias: {
        "@": resolve(__dirname, "./src")
      }
    }
  }
});

If you prefer to use a different alias than @, you’ll need to update the import statements when adding components.

Configure config

This is what this project’s tailwind.config.cjs file looks like:

tailwind.config.cjs
const { fontFamily } = require("tailwindcss/defaultTheme");
 
/** @type {import('tailwindcss').Config} */
export default {
  darkMode: ["class", '[data-kb-theme="dark"]'],
  content: [
    "src/routes/**/*.{ts,tsx,mdx}",
    "src/components/**/*.{ts,tsx}",
    "src/registry/**/*.{ts,tsx}"
  ],
  theme: {
    extend: {
      container: {
        center: true,
        padding: "2rem",
        screens: {
          "2xl": "1400px"
        }
      },
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))"
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))"
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))"
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))"
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))"
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))"
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))"
        }
      },
      borderRadius: {
        lg: `var(--radius)`,
        md: `calc(var(--radius) - 2px)`,
        sm: "calc(var(--radius) - 4px)"
      },
      fontFamily: {
        sans: ["Inter Variable", ...fontFamily.sans]
      },
      keyframes: {
        "accordion-down": {
          from: { height: 0 },
          to: { height: "var(--kb-accordion-content-height)" }
        },
        "accordion-up": {
          from: { height: "var(--kb-accordion-content-height)" },
          to: { height: 0 }
        },
        "collapsible-down": {
          from: { height: 0 },
          to: { height: "var(--kb-collapsible-content-height)" }
        },
        "collapsible-up": {
          from: { height: "var(--kb-collapsible-content-height)" },
          to: { height: 0 }
        }
      },
      animation: {
        "accordion-down": "accordion-down 0.2s ease-out",
        "accordion-up": "accordion-up 0.2s ease-out",
        "collapsible-down": "collapsible-down 0.2s ease-out",
        "collapsible-up": "collapsible-up 0.2s ease-out"
      }
    }
  },
  plugins: [require("tailwindcss-animate")]
};

or uno.config.ts

uno.config.ts
import { defineConfig, presetUno, transformerDirectives, transformerVariantGroup } from "unocss";
import presetAnimations from "unocss-preset-animations";
 
export default defineConfig({
  presets: [
    presetUno({
      dark: {
        dark: '[data-kb-theme="dark"]',
        light: '[data-kb-theme="light"]'
      }
    }),
    presetAnimations()
  ],
  transformers: [transformerVariantGroup(), transformerDirectives()],
  theme: {
    colors: {
      border: "hsl(var(--border))",
      input: "hsl(var(--input))",
      ring: "hsl(var(--ring))",
      background: "hsl(var(--background))",
      foreground: "hsl(var(--foreground))",
      primary: {
        DEFAULT: "hsl(var(--primary))",
        foreground: "hsl(var(--primary-foreground))"
      },
      secondary: {
        DEFAULT: "hsl(var(--secondary))",
        foreground: "hsl(var(--secondary-foreground))"
      },
      destructive: {
        DEFAULT: "hsl(var(--destructive))",
        foreground: "hsl(var(--destructive-foreground))"
      },
      muted: {
        DEFAULT: "hsl(var(--muted))",
        foreground: "hsl(var(--muted-foreground))"
      },
      accent: {
        DEFAULT: "hsl(var(--accent))",
        foreground: "hsl(var(--accent-foreground))"
      },
      popover: {
        DEFAULT: "hsl(var(--popover))",
        foreground: "hsl(var(--popover-foreground))"
      },
      card: {
        DEFAULT: "hsl(var(--card))",
        foreground: "hsl(var(--card-foreground))"
      }
    },
    borderRadius: {
      lg: `var(--radius)`,
      md: `calc(var(--radius) - 2px)`,
      sm: "calc(var(--radius) - 4px)"
    },
    animation: {
      keyframes: {
        "accordion-down":
          "{ from { height: 0 } to { height: var(--kb-accordion-content-height) } }",
        "accordion-up": "{ from { height: var(--kb-accordion-content-height) } to { height: 0 } }",
        "collapsible-down":
          "{ from { height: 0 } to { height: var(--kb-collapsible-content-height) } }",
        "collapsible-up":
          "{ from { height: var(--kb-collapsible-content-height) } to { height: 0 } }"
      },
      timingFns: {
        "accordion-down": "ease-out",
        "accordion-up": "ease-out",
        "collapsible-down": "ease-out",
        "collapsible-up": "ease-out"
      },
      durations: {
        "accordion-down": "0.2s",
        "accordion-up": "0.2s",
        "collapsible-down": "0.2s",
        "collapsible-up": "0.2s"
      }
    }
  }
});

Configure styles

Add the following to your src/app.css file. You can learn more about using CSS variables for theming in the theming section.

src/app.css
@tailwind base;
@tailwind components;
@tailwind utilities;
 
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 0 0% 3.9%;
 
    --card: 0 0% 100%;
    --card-foreground: 0 0% 3.9%;
 
    --popover: 0 0% 100%;
    --popover-foreground: 0 0% 3.9%;
 
    --primary: 0 0% 9%;
    --primary-foreground: 0 0% 98%;
 
    --secondary: 0 0% 96.1%;
    --secondary-foreground: 0 0% 9%;
 
    --muted: 0 0% 96.1%;
    --muted-foreground: 0 0% 45.1%;
 
    --accent: 0 0% 96.1%;
    --accent-foreground: 0 0% 9%;
 
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
 
    --border: 0 0% 89.8%;
    --input: 0 0% 89.8%;
    --ring: 0 0% 3.9%;
 
    --radius: 0.5rem;
  }
 
  [data-kb-theme="dark"] {
    --background: 0 0% 3.9%;
    --foreground: 0 0% 98%;
 
    --card: 0 0% 3.9%;
    --card-foreground: 0 0% 98%;
 
    --popover: 0 0% 3.9%;
    --popover-foreground: 0 0% 98%;
 
    --primary: 0 0% 98%;
    --primary-foreground: 0 0% 9%;
 
    --secondary: 0 0% 14.9%;
    --secondary-foreground: 0 0% 98%;
 
    --muted: 0 0% 14.9%;
    --muted-foreground: 0 0% 63.9%;
 
    --accent: 0 0% 14.9%;
    --accent-foreground: 0 0% 98%;
 
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
 
    --border: 0 0% 14.9%;
    --input: 0 0% 14.9%;
    --ring: 0 0% 83.1%;
  }
}
 
@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}

if you are using uno:

src/app.css
:root {
  --background: 0 0% 100%;
  --foreground: 0 0% 3.9%;
 
  --card: 0 0% 100%;
  --card-foreground: 0 0% 3.9%;
 
  --popover: 0 0% 100%;
  --popover-foreground: 0 0% 3.9%;
 
  --primary: 0 0% 9%;
  --primary-foreground: 0 0% 98%;
 
  --secondary: 0 0% 96.1%;
  --secondary-foreground: 0 0% 9%;
 
  --muted: 0 0% 96.1%;
  --muted-foreground: 0 0% 45.1%;
 
  --accent: 0 0% 96.1%;
  --accent-foreground: 0 0% 9%;
 
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 0 0% 98%;
 
  --border: 0 0% 89.8%;
  --input: 0 0% 89.8%;
  --ring: 0 0% 3.9%;
 
  --radius: 0.5rem;
}
 
[data-kb-theme="dark"] {
  --background: 0 0% 3.9%;
  --foreground: 0 0% 98%;
 
  --card: 0 0% 3.9%;
  --card-foreground: 0 0% 98%;
 
  --popover: 0 0% 3.9%;
  --popover-foreground: 0 0% 98%;
 
  --primary: 0 0% 98%;
  --primary-foreground: 0 0% 9%;
 
  --secondary: 0 0% 14.9%;
  --secondary-foreground: 0 0% 98%;
 
  --muted: 0 0% 14.9%;
  --muted-foreground: 0 0% 63.9%;
 
  --accent: 0 0% 14.9%;
  --accent-foreground: 0 0% 98%;
 
  --destructive: 0 62.8% 30.6%;
  --destructive-foreground: 0 0% 98%;
 
  --border: 0 0% 14.9%;
  --input: 0 0% 14.9%;
  --ring: 0 0% 83.1%;
}
 
* {
  @apply border-border;
}
body {
  @apply bg-background text-foreground;
}

Add a cn helper

I use a cn helper to make it easier to conditionally add Tailwind CSS classes. Here’s how I define it in src/libs/cn.ts:

src/libs/cn.ts
import type { ClassValue } from "clsx";
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
 
export const cn = (...classLists: ClassValue[]) => twMerge(clsx(classLists));

That’s it

You can now start adding components to your project.

npx shadcn-solid@latest add button

The command above will add the Button component to your project. You can then import it like this:

import { Button } from "@/components/ui/button"
 
export default function Home() {
  return (
    <div>
      <Button>Click me</Button>
    </div>
  )
}