Installation
Add @iammikz/srui to a Tailwind v4 project.
srui is a regular npm package. You need React 18+ and Tailwind CSS v4.
1. Install the package
pnpm add @iammikz/srui
2. Import the styles
In your global CSS entry (the file that imports tailwindcss), add srui's
token contract, its animations, and every preset you want available:
@import "tailwindcss";
@import "@iammikz/srui/theme.css";
@import "@iammikz/srui/animations.css";
@import "@iammikz/srui/presets/flat.css";
@import "@iammikz/srui/presets/glass.css";
@import "@iammikz/srui/presets/neumorphic.css";
@import "@iammikz/srui/presets/skeuomorphic.css";
@source "../node_modules/@iammikz/srui/dist";
Tailwind v4 automatically scans your project for class names but skips
node_modules by default. srui's component classes live inside
node_modules/@iammikz/srui/dist, so without the explicit @source line
the utilities those components rely on (bg-primary, surface, …) are
never generated and everything renders unstyled.
3. Wrap your app in UIProvider
UIProvider holds the active preset (data-style on <html>) and color
scheme (the dark class), and persists both to localStorage.
To avoid a flash of the wrong theme before React hydrates, also inline the
exported noFlashScript() into your document head:
import { createRoot } from "react-dom/client";
import { UIProvider, noFlashScript } from "@iammikz/srui";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<UIProvider>
<App />
</UIProvider>,
);
<script>
{/* replace this comment with the output of noFlashScript() */}
</script>
The copy-pasteable script (rendered here from noFlashScript()):
(function(){try{var s=localStorage.getItem('srui-style');var c=localStorage.getItem('srui-scheme');var sv=(s==='glass'||s==='neumorphic'||s==='skeuomorphic'||s==='flat')?s:'flat';var cv=(c==='light'||c==='dark'||c==='system')?c:'system';var dark=cv==='dark'||(cv==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);var e=document.documentElement;e.setAttribute('data-style',sv);e.classList.toggle('dark',dark);e.style.colorScheme=dark?'dark':'light';}catch(err){}})();
It reads the persisted srui-style / srui-scheme keys and applies
data-style + the dark class before first paint.
Not using Tailwind? The precompiled fallback
If your project doesn't use Tailwind v4, import the precompiled stylesheet
instead of steps 2's imports — it contains the tokens, presets, base styles
and every utility srui's components use (compiled with prefix(srui) so it
can't collide with your own classes):
@import "@iammikz/srui/styles.css";
Skip the @source line in this setup — there is nothing for Tailwind to
scan.
Vite setup walkthrough
Vite is this project's own supported consumer path. Assuming a standard
npm create vite React+TS app:
import { createRoot } from "react-dom/client";
import { UIProvider, noFlashScript } from "@iammikz/srui";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<UIProvider>
<App />
</UIProvider>,
);
Add the plugin and point Tailwind at your CSS entry:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
});
And the no-flash script inline in index.html's <head>:
(function(){try{var s=localStorage.getItem('srui-style');var c=localStorage.getItem('srui-scheme');var sv=(s==='glass'||s==='neumorphic'||s==='skeuomorphic'||s==='flat')?s:'flat';var cv=(c==='light'||c==='dark'||c==='system')?c:'system';var dark=cv==='dark'||(cv==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);var e=document.documentElement;e.setAttribute('data-style',sv);e.classList.toggle('dark',dark);e.style.colorScheme=dark?'dark':'light';}catch(err){}})();
That's the whole setup — the same recipe this site's own apps/docs uses.