Getting StartedInstallation

Manual

Add dependencies to your project manually.

Steps

Add Tailwind CSS

Components are styled using Tailwind CSS v4. You need to install Tailwind CSS in your project.

Follow the Tailwind CSS installation instructions to get started.

Add this import in your main css file (e.g. src/index.css):

@import "tailwindcss";

Add dependencies

Add the following dependencies to your project:

npm install shadcn tw-animate-css clsx class-variance-authority tailwind-merge @exawizards/exabase-design-system-icons-react

Configure path aliases

We use the @/* alias. This is how to set it up in tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "paths": { 
      "@/*": ["./src/*"] 
    } 
  }
}

You may also need to configure your bundler to resolve the alias. Refer to your framework's documentation for details.

Configure styles

Add the following to your main CSS file. You can learn more about using CSS variables for theming in the theming section.

global.css
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";

@custom-variant dark (&:is(.dark *));

@theme inline {
  --font-sans: var(--font-inter), var(--font-noto-sans-jp), sans-serif;
  --radius-xs: calc(var(--radius) - 6px);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
  --radius-2xl: calc(var(--radius) + 8px);
  --radius-3xl: calc(var(--radius) + 12px);
  --radius-4xl: calc(var(--radius) + 16px);
  --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-hovered: var(--primary-hovered);
  --color-primary-pressed: var(--primary-pressed);
  --color-primary-foreground: var(--primary-foreground);
  --color-primary-text: var(--primary-text);
  --color-secondary: var(--secondary);
  --color-secondary-hovered: var(--secondary-hovered);
  --color-secondary-pressed: var(--secondary-pressed);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-hovered: var(--destructive-hovered);
  --color-destructive-pressed: var(--destructive-pressed);
  --color-destructive-foreground: var(--destructive-foreground);
  --color-destructive-text: var(--destructive-text);
  --color-destructive-muted: var(--destructive-muted);
  --color-info: var(--info);
  --color-info-foreground: var(--info-foreground);
  --color-info-text: var(--info-text);
  --color-info-muted: var(--info-muted);
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
  --color-success-text: var(--success-text);
  --color-success-muted: var(--success-muted);
  --color-warning: var(--warning);
  --color-warning-foreground: var(--warning-foreground);
  --color-warning-text: var(--warning-text);
  --color-warning-muted: var(--warning-muted);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-pressed: var(--accent-pressed);
  --color-accent-foreground: var(--accent-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --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);
}

:root {
  --radius: 0.625rem;
  --background: rgb(255, 255, 255); /* exaBase White */
  --foreground: rgb(8, 10, 12); /* exaBase Slate 99 */
  --card: rgb(255, 255, 255); /* = background */
  --card-foreground: rgb(8, 10, 12); /* = foreground */
  --popover: rgb(255, 255, 255); /* = background */
  --popover-foreground: rgb(8, 10, 12); /* = foreground */
  --primary: rgb(37, 99, 244); /* exaBase Blue 50 */
  --primary-hovered: rgb(58, 114, 245); /* + White 10% */
  --primary-pressed: rgb(81, 130, 246); /* + White 20% */
  --primary-foreground: rgb(255, 255, 255); /* exaBase White */
  --primary-text: rgb(37, 99, 244); /* = primary */
  --secondary: rgba(103, 120, 145, 0.1); /* exaBase Slate 50 10% */
  --secondary-hovered: rgba(103, 120, 145, 0.2); /* exaBase Slate 50 20% */
  --secondary-pressed: rgba(103, 120, 145, 0.3); /* exaBase Slate 50 30% */
  --secondary-foreground: rgb(8, 10, 12); /* exaBase Slate 99 */
  --destructive: rgb(245, 20, 10); /* exaBase Red 50 */
  --destructive-hovered: rgb(246, 55, 47); /* + White 15% */
  --destructive-pressed: rgb(247, 90, 83); /* + White 30% */
  --destructive-foreground: rgb(255, 255, 255); /* exaBase White */
  --destructive-text: rgb(245, 20, 10); /* = destructive */
  --destructive-muted: rgb(254, 227, 226); /* exaBase Red 3 */
  --info: rgb(0, 177, 242); /* exaBase Cyan 50 */
  --info-foreground: rgb(255, 255, 255); /* exaBase White */
  --info-text: rgb(0, 152, 208); /* exaBase Cyan 60 */
  --info-muted: rgb(224, 246, 253); /* exaBase Cyan 3 */
  --success: rgb(17, 156, 17); /* exaBase Green 50 */
  --success-foreground: rgb(255, 255, 255); /* exaBase White */
  --success-text: rgb(11, 138, 11); /* exaBase Green 60 */
  --success-muted: rgb(226, 243, 226); /* exaBase Green 3 */
  --warning: rgb(249, 181, 0); /* exaBase Amber 50 */
  --warning-foreground: rgb(8, 10, 12); /* exaBase Slate 99 */
  --warning-text: rgb(179, 130, 0); /* exaBase Amber 70 */
  --warning-muted: rgb(254, 246, 224); /* exaBase Amber 3 */
  --muted: rgb(237, 239, 242); /* exaBase Slate 3 */
  --muted-foreground: rgb(103, 120, 145); /* exaBase Slate 50 */
  --accent: rgba(103, 120, 145, 0.1); /* = secondary */
  --accent-pressed: rgba(103, 120, 145, 0.2); /* = secondary-hovered */
  --accent-foreground: rgb(8, 10, 12); /* = secondary-foreground */
  --border: rgb(212, 217, 224); /* exaBase Slate 10 */
  --input: rgb(212, 217, 224); /* exaBase Slate 10 */
  --ring: rgb(37, 99, 244); /* = primary */
  --sidebar: rgb(249, 250, 251); /* exaBase Slate 1 */
  --sidebar-foreground: rgb(8, 10, 12); /* = foreground */
  --sidebar-primary: rgb(37, 99, 244); /* = primary */
  --sidebar-primary-foreground: rgb(255, 255, 255); /* = primary-foreground */
  --sidebar-accent: rgba(103, 120, 145, 0.1); /* = accent */
  --sidebar-accent-foreground: rgb(8, 10, 12); /* = accent-foreground */
  --sidebar-border: rgb(212, 217, 224); /* = border */
  --sidebar-ring: rgb(37, 99, 244); /* = ring */
}

.dark {
  --background: rgb(16, 19, 23); /* exaBase Slate 97 */
  --foreground: rgb(237, 239, 242); /* exaBase Slate 3 */
  --card: rgb(16, 19, 23); /* = background */
  --card-foreground: rgb(237, 239, 242); /* = foreground */
  --popover: rgb(16, 19, 23); /* = background */
  --popover-foreground: rgb(237, 239, 242); /* = foreground */
  --primary: rgb(37, 99, 244); /* = light */
  --primary-hovered: rgb(58, 114, 245); /* = light */
  --primary-pressed: rgb(81, 130, 246); /* = light */
  --primary-foreground: rgb(255, 255, 255); /* = light */
  --primary-text: rgb(76, 127, 246); /* exaBase Blue 40 */
  --secondary: rgba(237, 239, 242, 0.08); /* exaBase Slate 3 8% */
  --secondary-hovered: rgba(237, 239, 242, 0.16); /* exaBase Slate 3 16% */
  --secondary-pressed: rgba(237, 239, 242, 0.24); /* exaBase Slate 3 24% */
  --secondary-foreground: rgb(237, 239, 242); /* exaBase Slate 3 */
  --destructive: rgb(247, 62, 54); /* exaBase Red 40 */
  --destructive-hovered: rgb(248, 91, 84); /* + White 15% */
  --destructive-pressed: rgb(249, 120, 114); /* + White 30% */
  --destructive-foreground: rgb(255, 255, 255); /* exaBase White */
  --destructive-text: rgb(247, 62, 54); /* exaBase Red 40 */
  --destructive-muted: rgb(77, 3, 0); /* exaBase Red 95 */
  --info: rgb(0, 177, 242); /* = light */
  --info-foreground: rgb(255, 255, 255); /* = light */
  --info-text: rgb(0, 177, 242); /* exaBase Cyan 50 */
  --info-muted: rgb(0, 53, 73); /* exaBase Cyan 95 */
  --success: rgb(17, 156, 17); /* = light */
  --success-foreground: rgb(255, 255, 255); /* = light */
  --success-text: rgb(17, 156, 17); /* exaBase Green 50 */
  --success-muted: rgb(0, 52, 0); /* exaBase Green 95 */
  --warning: rgb(249, 181, 0); /* = light */
  --warning-foreground: rgb(8, 10, 12); /* = light */
  --warning-text: rgb(249, 181, 0); /* exaBase Amber 50 */
  --warning-muted: rgb(75, 54, 0); /* exaBase Amber 95 */
  --muted: rgb(31, 36, 44); /* exaBase Slate95 */
  --muted-foreground: rgb(130, 144, 165); /* exaBase Slate 40 */
  --accent: rgba(237, 239, 242, 0.08); /* = secondary */
  --accent-pressed: rgba(237, 239, 242, 0.16); /* = secondary-hovered */
  --accent-foreground: rgb(237, 239, 242); /* = secondary-foreground */
  --border: rgb(45, 53, 64); /* exaBase Slate 90 */
  --input: rgb(45, 53, 64); /* exaBase Slate 90 */
  --ring: rgb(37, 99, 244); /* = primary */
  --sidebar: rgb(31, 36, 44); /* exaBase Slate 95 */
  --sidebar-foreground: rgb(237, 239, 242); /* = foreground */
  --sidebar-primary: rgb(37, 99, 244); /* = primary */
  --sidebar-primary-foreground: rgb(255, 255, 255); /* = primary-foreground */
  --sidebar-accent: rgba(237, 239, 242, 0.08); /* = accent */
  --sidebar-accent-foreground: rgb(237, 239, 242); /* = accent-foreground */
  --sidebar-border: rgb(45, 53, 64); /* = border */
  --sidebar-ring: rgb(37, 99, 244); /* = ring */
}

@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}

Add utilities

We use a cn helper to make it easier to conditionally add Tailwind CSS classes. Here's how to define it in lib/utils.ts:

lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Create components.json

Create a components.json file in the root of your project:

components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "src/index.css",
    "baseColor": "slate",
    "cssVariables": true,
    "prefix": ""
  },
  "iconLibrary": "lucide",
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "registries": {
    "@exabase": "https://exawizards.com/exabase/design/registry/{name}.json"
  }
}

Add fonts

Install the Inter and Noto Sans JP fonts used in the design system.

Embed code in the <head> of your html:

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Noto+Sans+JP:wght@100..900&display=swap"
  rel="stylesheet"
/>

Or @import in your css:

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Noto+Sans+JP:wght@100..900&display=swap");

Add components

You can now start adding components to your project. Each component must be installed individually.

npx shadcn@latest add @exabase/button

On this page