Vite + React
Install: Vite + React
Setup recipe for adding
@devalok/shilp-sutrato a Vite + React SPA.
1. Detect
You are in this recipe if:
vite.config.{ts,js,mjs}exists at the project rootpackage.jsonlists"vite"and"react"src/main.{tsx,jsx}is the entry that callscreateRoot(...).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-table | pnpm 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-otp | pnpm add input-otp |
@devalok/shilp-sutra/composed/file-preview | pnpm add react-pdf react-zoom-pan-pinch |
@devalok/shilp-sutra/composed/markdown-viewer | pnpm add react-markdown react-syntax-highlighter |
Any Icon / IconButton with Tabler icons | pnpm 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.csssrc/main.csssrc/styles/globals.csssrc/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/viteand@tailwindcss/postcsstogether. 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/CSSwill 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(notp-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}withpresets: [shilpSutra]— JS preset removed. - ❌ Try to use
next-themeshere — it requires Next. Use the bootstrap script +useColorModeshown in § 5.