Install

Vite + React

Install: Vite + React

Setup recipe for adding @devalok/shilp-sutra to a Vite + React SPA.

1. Detect

You are in this recipe if:

  • vite.config.{ts,js,mjs} exists at the project root
  • package.json lists "vite" and "react"
  • src/main.{tsx,jsx} is the entry that calls createRoot(...).render(<App />)

This recipe also covers Vite + React + React Router (any version) — the design system is router-agnostic.

If you are using Remix (which now runs on Vite), use install-remix.md. If you are using TanStack Start, use install-tanstack-start.md.

2. Install dependencies

# pnpm
pnpm add @devalok/shilp-sutra framer-motion
pnpm add -D tailwindcss@^4 @tailwindcss/vite

# npm
npm install @devalok/shilp-sutra framer-motion
npm install -D tailwindcss@^4 @tailwindcss/vite

# yarn
yarn add @devalok/shilp-sutra framer-motion
yarn add -D tailwindcss@^4 @tailwindcss/vite

# bun
bun add @devalok/shilp-sutra framer-motion
bun add -d tailwindcss@^4 @tailwindcss/vite

Add only if rendering <Toaster />:

pnpm add sonner

2a. Optional peer dependencies (install ONLY when importing the matching subpath)

Some components ship hard peers as optional. Install BEFORE first import or vite dev / vite build will fail with Failed to resolve import. Skip if you only use core components.

When you import…Install
@devalok/shilp-sutra/ui/charts/*pnpm add d3-array d3-axis d3-format d3-interpolate d3-scale d3-selection d3-shape d3-time-format d3-transition
@devalok/shilp-sutra/ui/data-tablepnpm add @tanstack/react-table @tanstack/react-virtual
@devalok/shilp-sutra/composed/date-picker (+ DateRange, DateTime, Calendar)pnpm add date-fns
@devalok/shilp-sutra/composed/rich-text-editor (+ RichChatInput, RichTextViewer)pnpm add @tiptap/react @tiptap/starter-kit @tiptap/extension-placeholder
@devalok/shilp-sutra/ui/input-otppnpm add input-otp
@devalok/shilp-sutra/composed/file-previewpnpm add react-pdf react-zoom-pan-pinch
@devalok/shilp-sutra/composed/markdown-viewerpnpm add react-markdown react-syntax-highlighter
Any Icon / IconButton with Tabler iconspnpm add @tabler/icons-react

3. Wire Tailwind 4 in vite.config.ts

Use the official Tailwind 4 Vite plugin (faster than PostCSS for Vite):

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [react(), tailwindcss()],
});

If the project already uses PostCSS for other reasons, you can use @tailwindcss/postcss instead — see install-next-app-router.md § 3. Stick with one approach; do not load both.

4. Wire tokens in the global CSS

Common CSS entry paths in priority order:

  • src/index.css
  • src/main.css
  • src/styles/globals.css
  • src/App.css

If none exists, create src/index.css. Set or merge:

@import "tailwindcss";
@import "@devalok/shilp-sutra/css";

Import it once from the entry (src/main.tsx):

import "./index.css";

5. Theme toggle (no next-themes here)

Vite has no built-in theme provider. Use the design system's useColorMode hook with a small bootstrap script to avoid a flash of wrong theme.

Add the bootstrap to index.html (in <head>, before any stylesheet):

<script>
  (function () {
    try {
      var stored = localStorage.getItem("theme");
      var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      var dark = stored === "dark" || (!stored && prefersDark);
      if (dark) document.documentElement.classList.add("dark");
    } catch (e) {}
  })();
</script>

Wire the runtime hook from anywhere in the app (e.g., a header button):

import { useColorMode } from "@devalok/shilp-sutra/hooks/use-color-mode";

export function ThemeToggle() {
  const { mode, toggle } = useColorMode();
  return (
    <button onClick={toggle} aria-label="Toggle theme">
      {mode === "dark" ? "☀" : "☾"}
    </button>
  );
}

6. Mount Toaster (optional)

If you installed sonner, mount the Toaster once near the app root:

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Toaster } from "@devalok/shilp-sutra/ui/toaster";
import { App } from "./App";
import "./index.css";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
    <Toaster />
  </StrictMode>,
);

7. Verify

Replace src/App.tsx:

import { Button } from "@devalok/shilp-sutra/ui/button";
import { Stack } from "@devalok/shilp-sutra/ui/stack";
import { Text } from "@devalok/shilp-sutra/ui/text";

export function App() {
  return (
    <Stack className="p-ds-08" gap="ds-04">
      <Text variant="heading-2xl">Hello, Shilp Sutra</Text>
      <Stack direction="row" gap="ds-03">
        <Button>Primary</Button>
        <Button variant="soft">Soft</Button>
      </Stack>
    </Stack>
  );
}

Run pnpm dev and open the printed Vite URL. Expected output matches Next App Router § 7.

8. Gotchas (Vite-specific)

  • @tailwindcss/vite and @tailwindcss/postcss together. Pick one — running both causes utilities to be processed twice and CSS bloat.
  • CSS import paths in HMR. Vite is strict about case-sensitivity even on macOS. @devalok/shilp-sutra/CSS will not resolve; use the lowercase /css.
  • Multiple framer-motion copies. Same fix as Next — see install-next-app-router.md § 8.
  • Spacing utilities. Use p-ds-04 (not p-4). Tailwind composite text utilities: text-heading-xl, text-body-md, text-code.

9. What NOT to do

  • ❌ Add @devalok/shilp-sutra/tailwind — the export was removed in 0.38.
  • ❌ Add a tailwind.config.{ts,js} with presets: [shilpSutra] — JS preset removed.
  • ❌ Try to use next-themes here — it requires Next. Use the bootstrap script + useColorMode shown in § 5.