Getting started

Installation

How to install and configure LibravelUI in your project.

Prerequisites

LibravelUI requires the following:

  • React 18 or later
  • Tailwind CSS 3.4 or later (v4 supported)
  • Node.js 18 or later

Quick Start

The fastest way to start is using one of our Starter Kits. These are pre-configured repositories with LibravelUI, Tailwind CSS v4, and TypeScript ready to go.

Framework Guide

Starter template
A ready-to-use project foundation with essential tools and configuration to help you build and launch faster using LibravelUI.

CLI Installation

If you already have a project, use the CLI to configure LibravelUI automatically.

1. Initialize

Run init to set up dependencies and configuration.

npx @libravelui@latest init

2. Add Components

Use add to specific components to your project.

npx @libravelui@latest add button

Manual Installation

If you prefer to set up everything manually, follow these steps.

1. Install Dependencies

Install the core dependencies and utilities required by LibravelUI components.

npm install react-aria-components motion lucide-react clsx tailwind-merge class-variance-authority tailwindcss-react-aria-components tw-animate-css

2. Configure Tailwind CSS

Add the tailwindcss-react-aria-components plugin to your Tailwind configuration.

Tailwind v4 (CSS):

@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";
@plugin "tw-animate-css";

Tailwind v3 (JS):

// tailwind.config.js
module.exports = {
  content: [
    // ...
    "./node_modules/tw-animate-css/**/*.js",
  ],
  plugins: [
    require("tailwindcss-react-aria-components"),
    require("tw-animate-css"),
  ],
};

3. Add Utility Helper

Create a lib/utils.ts file for the cn helper function.

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

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

4. Add Global Styles

Add the following CSS variables to your global CSS file (e.g., globals.css) to define the design tokens.

@import "tailwindcss";
@import "tw-animate-css";

@plugin 'tailwindcss-react-aria-components';

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

:root {
  --background: oklch(0.9232 0.0026 48.7171);
  --foreground: oklch(0.2795 0.0368 260.031);
  --card: oklch(0.9699 0.0013 106.4238);
  --card-foreground: oklch(0.2795 0.0368 260.031);
  --popover: oklch(0.9699 0.0013 106.4238);
  --popover-foreground: oklch(0.2795 0.0368 260.031);
  --primary: oklch(0.5854 0.2041 277.1173);
  --primary-foreground: oklch(1 0 0);
  --secondary: oklch(0.8687 0.0043 56.366);
  --secondary-foreground: oklch(0.4461 0.0263 256.8018);
  --muted: oklch(0.9232 0.0026 48.7171);
  --muted-foreground: oklch(0.551 0.0234 264.3637);
  --accent: oklch(0.9376 0.026 321.9388);
  --accent-foreground: oklch(0.3729 0.0306 259.7328);
  --destructive: oklch(0.6368 0.2078 25.3313);
  --destructive-foreground: oklch(1 0 0);
  --border: oklch(0.8687 0.0043 56.366);
  --input: oklch(0.8687 0.0043 56.366);
  --ring: oklch(0.5854 0.2041 277.1173);
  --chart-1: oklch(0.5854 0.2041 277.1173);
  --chart-2: oklch(0.5106 0.2301 276.9656);
  --chart-3: oklch(0.4568 0.2146 277.0229);
  --chart-4: oklch(0.3984 0.1773 277.3662);
  --chart-5: oklch(0.3588 0.1354 278.6973);
  --sidebar: oklch(0.8687 0.0043 56.366);
  --sidebar-foreground: oklch(0.2795 0.0368 260.031);
  --sidebar-primary: oklch(0.5854 0.2041 277.1173);
  --sidebar-primary-foreground: oklch(1 0 0);
  --sidebar-accent: oklch(0.9376 0.026 321.9388);
  --sidebar-accent-foreground: oklch(0.3729 0.0306 259.7328);
  --sidebar-border: oklch(0.8687 0.0043 56.366);
  --sidebar-ring: oklch(0.5854 0.2041 277.1173);
  --radius: 0.625rem;
  --shadow-2xs: 2px 2px 10px 4px hsl(240 4% 60% / 0.09);
  --shadow-xs: 2px 2px 10px 4px hsl(240 4% 60% / 0.09);
  --shadow-sm:
    2px 2px 10px 4px hsl(240 4% 60% / 0.18),
    2px 1px 2px 3px hsl(240 4% 60% / 0.18);
  --shadow:
    2px 2px 10px 4px hsl(240 4% 60% / 0.18),
    2px 1px 2px 3px hsl(240 4% 60% / 0.18);
  --shadow-md:
    2px 2px 10px 4px hsl(240 4% 60% / 0.18),
    2px 2px 4px 3px hsl(240 4% 60% / 0.18);
  --shadow-lg:
    2px 2px 10px 4px hsl(240 4% 60% / 0.18),
    2px 4px 6px 3px hsl(240 4% 60% / 0.18);
  --shadow-xl:
    2px 2px 10px 4px hsl(240 4% 60% / 0.18),
    2px 8px 10px 3px hsl(240 4% 60% / 0.18);
  --shadow-2xl: 2px 2px 10px 4px hsl(240 4% 60% / 0.45);
  --tracking-normal: 0em;
  --spacing: 0.25rem;

  --font-tasa-orbiter: "TASA Orbiter";

  --font-sans:
    var(--font-bricolage-grotesque), var(--font-tasa-orbiter),
    var(--font-geist), ui-sans-serif, system-ui, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --font-serif: var(--font-domine), serif;
  --font-mono: var(--font-geist-mono), var(--font-jetbrains-mono), monospace;
}

.dark {
  --background: oklch(0.2042 0.0019 106.57);
  --foreground: oklch(0.9978 0.001061 17.1758);
  --card: oklch(0.2304 0.0019 106.55);
  --card-foreground: oklch(0.9619 0.0011 17.18);
  --popover: var(--card);
  --popover-foreground: var(--card-foreground);
  --primary: oklch(0.8841 0.1072 169.26);
  --primary-foreground: oklch(0.2244 0.0074 67.437);
  --secondary: oklch(0.2382 0.0015 197.06);
  --secondary-foreground: oklch(0.8717 0.0093 258.3382);
  --muted: oklch(0.34 0.004 330);
  --muted-foreground: oklch(0.7137 0.0192 261.3246);
  --accent: oklch(0.8841 0.1072 169.26 / 35%);
  --accent-foreground: oklch(0.8717 0.0093 258.3382);
  --destructive: oklch(0.6368 0.2078 25.3313);
  --destructive-foreground: oklch(0.2244 0.0074 67.437);
  --border: oklch(0.2382 0.0015 197.06);
  --input: oklch(0.2382 0.0015 197.06);
  --ring: var(--primary);
  --chart-1: var(--primary);
  --chart-2: oklch(0.5854 0.2041 277.1173);
  --chart-3: oklch(0.5106 0.2301 276.9656);
  --chart-4: oklch(0.4568 0.2146 277.0229);
  --chart-5: oklch(0.3984 0.1773 277.3662);
  --sidebar: var(--card);
  --sidebar-foreground: var(--card-foreground);
  --sidebar-primary: var(--primary);
  --sidebar-primary-foreground: oklch(0.2244 0.0074 67.437);
  --sidebar-accent: var(--accent);
  --sidebar-accent-foreground: oklch(0.8717 0.0093 258.3382);
  --sidebar-border: oklch(0.2382 0.0015 197.06);
  --sidebar-ring: var(--primary);
  --shadow-2xs: 2px 2px 10px 4px hsl(0 0% 0% / 0.09);
  --shadow-xs: 2px 2px 10px 4px hsl(0 0% 0% / 0.09);
  --shadow-sm:
    2px 2px 10px 4px hsl(0 0% 0% / 0.18), 2px 1px 2px 3px hsl(0 0% 0% / 0.18);
  --shadow:
    2px 2px 10px 4px hsl(0 0% 0% / 0.18), 2px 1px 2px 3px hsl(0 0% 0% / 0.18);
  --shadow-md:
    2px 2px 10px 4px hsl(0 0% 0% / 0.18), 2px 2px 4px 3px hsl(0 0% 0% / 0.18);
  --shadow-lg:
    2px 2px 10px 4px hsl(0 0% 0% / 0.18), 2px 4px 6px 3px hsl(0 0% 0% / 0.18);
  --shadow-xl:
    2px 2px 10px 4px hsl(0 0% 0% / 0.18), 2px 8px 10px 3px hsl(0 0% 0% / 0.18);
  --shadow-2xl: 2px 2px 10px 4px hsl(0 0% 0% / 0.45);
}

@theme inline {
  --font-sans: var(--font-sans);
  --font-serif: var(--font-serif);
  --font-mono: var(--font-mono);

  --font-bricolage-grotesque: var(--font-bricolage-grotesque);
  --font-tasa-orbiter: var(--font-tasa-orbiter);
  --font-afacad-flux: var(--font-afacad-flux);

  --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-destructive-foreground: var(--destructive-foreground);
  --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);

  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  --shadow-2xs: var(--shadow-2xs);
  --shadow-xs: var(--shadow-xs);
  --shadow-sm: var(--shadow-sm);
  --shadow: var(--shadow);
  --shadow-md: var(--shadow-md);
  --shadow-lg: var(--shadow-lg);
  --shadow-xl: var(--shadow-xl);
  --shadow-2xl: var(--shadow-2xl);

  --animate-marquee: marquee 30s linear infinite;
  --animate-marqueeY: marqueeY 200s linear infinite;
}

@keyframes disclosure-collapsed {
  from {
    height: var(--disclosure-height);
  }
  to {
    height: 0;
  }
}

@keyframes disclosure-expanded {
  from {
    height: 0;
  }
  to {
    height: var(--disclosure-height);
  }
}

@keyframes marquee {
  0% {
    transform: translateX(0%);
  }
  100% {
    transform: translateX(calc(-100% - var(--gap)));
  }
}

@keyframes marqueeY {
  0% {
    transform: translateY(0%);
  }
  100% {
    transform: translateY(calc(-100% - var(--gap)));
  }
}

Next Steps

Now you are ready to add components to your project. Check out the Components section to see what's available.