@ideasui/theme
v0.0.4
Published
Tailwind CSS v4 theme system for IdeasUI
Maintainers
Readme
@ideasui/theme
The official design system and theme engine for IdeasUI — built on Tailwind CSS v4 and modern CSS.
Features
- 🎨 Unified Design System — Centralized tokens for colors, typography, spacing, and more
- 🌗 Dark Mode First — Native light/dark support using OKLCH color spaces
- 🧩 Tailwind CSS v4 Plugin — Seamless integration with Tailwind's utility classes
- ⚡ Zero Runtime Overhead — Tokens compiled to CSS variables at build time
- 🔄 Type-Safe — Full TypeScript support for theme configuration and overrides
Installation
npm install @ideasui/theme
# or
pnpm add @ideasui/themeSetup
Pick one of the following options.
Option 1 — CSS Import · Recommended
The simplest setup. Just import Tailwind and the prebuilt theme stylesheet.
/* globals.css */
@import 'tailwindcss';
@import '@ideasui/theme/theme.css';No
tailwind.config.tsneeded. The theme CSS already includes all plugin output.
Option 2 — Tailwind Config (Classic)
Add the plugin via a tailwind.config.ts file and reference it from your CSS.
// tailwind.config.ts
import { ideasUIPlugin } from '@ideasui/theme/plugin';
export default {
plugins: [ideasUIPlugin()],
};/* globals.css */
@import 'tailwindcss';
@config '../tailwind.config.ts';
@source '../../../node_modules/@ideasui/*/.{js,ts,jsx,tsx,mdx,css}';Option 3 — Inline Plugin (CSS-first)
Reference the plugin directly from your CSS without a separate config file.
/* globals.css */
@import 'tailwindcss';
@config '../plugin.ts';// plugin.ts
import { ideasUIPlugin } from '@ideasui/theme/plugin';
export default ideasUIPlugin();Add Theme Provider (React / Next.js) — Optional
Only needed if you want runtime theme switching (e.g. a light/dark toggle). Skip this if you're using a static theme.
Wrap your app with ThemeProvider to enable theme switching and persistence.
// app/providers.tsx
import { ThemeProvider } from '@ideasui/theme';
export function Providers({ children }) {
return <ThemeProvider defaultTheme="system">{children}</ThemeProvider>;
}Prevent FOUC (SSR / Next.js)
// app/layout.tsx
import { ThemeScript } from '@ideasui/theme';
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<ThemeScript />
</head>
<body>{children}</body>
</html>
);
}Token Architecture
| Tier | Examples |
| -------------- | ----------------------------------------------------- |
| Primitives | Raw OKLCH color values (primary-500, neutral-100) |
| Semantic | Role aliases (surface.elevated, content.primary) |
| Component | Component-specific tokens (button.base) |
Using Tokens
// Tailwind utilities
<div className="bg-surface-elevated text-content-primary rounded-lg p-4">
<button className="bg-primary-500 hover:bg-primary-600 text-white">Click</button>
</div>/* CSS variables */
.my-element {
background: var(--ideasui-color-surface-elevated);
color: var(--ideasui-color-content-primary);
}Customization
All customization is done through ideasUIPlugin(). Every option is optional — use only what you need.
Global Options
| Option | Type | Default | Description |
| ------------------- | ----------------------------- | --------- | ---------------------------------------- |
| defaultTheme | 'light' \| 'dark' \| string | 'light' | Initial active theme |
| disableAnimations | boolean | false | Globally disable all animations |
| designTokens | TokenOverrides | — | Override design tokens across all themes |
| semanticTokens | SemanticTokenOverrides | — | Override semantic color tokens globally |
| themes | { light?, dark? } | — | Per-theme color and token overrides |
ideasUIPlugin({
defaultTheme: 'dark',
disableAnimations: false,
});Colors
Override brand colors per-theme. Values can be any valid CSS color — OKLCH is recommended for precision.
ideasUIPlugin({
themes: {
light: {
colors: {
primary: {
500: 'oklch(0.65 0.25 145)', // custom green primary
600: 'oklch(0.55 0.22 145)',
},
secondary: {
500: 'oklch(0.60 0.20 30)', // warm coral
},
},
},
dark: {
colors: {
primary: {
500: 'oklch(0.70 0.20 145)',
},
},
},
},
});Available palettes: primary, secondary, tertiary, neutral, success, danger, warning, info
Available shades: 50 100 200 300 400 500 600 700 800 900 950
Design Tokens
Override any design token globally (all themes) or per-theme. Custom keys create new Tailwind utilities automatically.
Spacing
ideasUIPlugin({
designTokens: {
spacing: {
custom: '3px', // → p-custom, m-custom, gap-custom …
18: '4.5rem', // → p-18, m-18 …
},
},
});Border Radius
ideasUIPlugin({
designTokens: {
borderRadius: {
custom: '5px', // → rounded-custom
lg: '1rem', // override existing
},
},
});Border Width & Color
ideasUIPlugin({
designTokens: {
borderWidth: { custom: '1px' }, // → border-custom
borderColor: { custom: 'red' }, // → border-custom color
},
});Typography
ideasUIPlugin({
designTokens: {
fontSize: { custom: '12px' }, // → text-custom
fontFamily: { custom: 'Arial' }, // → font-custom
fontWeight: { custom: 'bold' }, // → font-custom
letterSpacing: { custom: '1px' }, // → tracking-custom
},
});Shadows
ideasUIPlugin({
designTokens: {
boxShadow: { custom: '0 0 0 1px red' }, // → shadow-custom
},
});Motion
ideasUIPlugin({
designTokens: {
duration: { custom: '1s' }, // → duration-custom
easing: { custom: 'ease-in-out' }, // → ease-custom
animation: { custom: 'spin 1s linear infinite' }, // → animate-custom
keyframes: {
custom: {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(360deg)' },
},
},
},
});Opacity, Z-Index & Blur
ideasUIPlugin({
designTokens: {
opacity: { custom: '0.5' }, // → opacity-custom
zIndex: { custom: '100' }, // → z-custom
blur: { custom: '10px' }, // → blur-custom
},
});Semantic Tokens
Override role-based colors (surfaces, content, borders) per-theme. Values are CSS color strings or var() references.
ideasUIPlugin({
themes: {
light: {
semanticTokens: {
surface: {
base: 'oklch(1 0 0)', // bg-surface-base
elevated: 'oklch(0.98 0.01 240)',
},
content: {
primary: 'oklch(0.2 0.02 240)', // text-content-primary
secondary: 'oklch(0.4 0.02 240)',
},
border: {
default: 'oklch(0.85 0 0)', // border-default
},
},
},
},
});Per-Theme Design Tokens
Design tokens can also be scoped to a specific theme:
ideasUIPlugin({
themes: {
light: {
designTokens: {
boxShadow: { md: '0 4px 12px 0 rgba(0,0,0,0.08)' },
},
},
dark: {
designTokens: {
boxShadow: { md: '0 4px 12px 0 rgba(0,0,0,0.4)' },
},
},
},
});CSS-only Customization
If you're using Option 1 (CSS Import) or prefer not to touch tailwind.config.ts, override any token directly in CSS.
Important: Color values are stored as bare OKLCH components (without the
oklch()wrapper) because the theme wraps them at consumption time viaoklch(var(...)). Use the same format when overriding.
Colors
:root {
/* Shades 50–950, stored as "L C H" components */
--ideasui-color-primary-500: 0.65 0.25 145;
--ideasui-color-primary-600: 0.55 0.22 145;
--ideasui-color-secondary-500: 0.6 0.2 30;
}
.dark,
[data-ideasui-theme='dark'] {
--ideasui-color-primary-500: 0.7 0.2 145;
}Available palettes: primary secondary tertiary neutral success danger warning info
Available shades: 50 100 200 300 400 500 600 700 800 900 950
Semantic Tokens
:root {
/* Surfaces — reference palette vars or provide bare L C H */
--ideasui-color-surface-base: var(--ideasui-color-neutral-50);
--ideasui-color-surface-elevated: var(--ideasui-color-neutral-100);
--ideasui-color-surface-muted: var(--ideasui-color-neutral-200);
--ideasui-color-surface-strong: var(--ideasui-color-neutral-300);
--ideasui-color-surface-inverse: var(--ideasui-color-neutral-900);
/* Content (text) */
--ideasui-color-content-primary: var(--ideasui-color-neutral-900);
--ideasui-color-content-secondary: var(--ideasui-color-neutral-700);
--ideasui-color-content-tertiary: var(--ideasui-color-neutral-600);
--ideasui-color-content-muted: var(--ideasui-color-neutral-500);
--ideasui-color-content-disabled: var(--ideasui-color-neutral-400);
--ideasui-color-content-inverse: var(--ideasui-color-neutral-50);
/* Borders */
--ideasui-color-border-default: var(--ideasui-color-neutral-200);
--ideasui-color-border-subtle: var(--ideasui-color-neutral-100);
--ideasui-color-border-strong: var(--ideasui-color-neutral-300);
--ideasui-color-border-focus: var(--ideasui-color-primary-500);
--ideasui-color-border-danger: var(--ideasui-color-danger-500);
}Spacing
:root {
--ideasui-spacing-custom: 3px; /* new → p-custom, m-custom, gap-custom */
--ideasui-spacing-4: 1.25rem; /* override existing */
}Border Radius
:root {
--ideasui-radius-custom: 5px; /* new → rounded-custom */
--ideasui-radius-lg: 0.75rem; /* override existing */
}Typography
:root {
--ideasui-font-sans: 'Geist', ui-sans-serif, system-ui, sans-serif;
--ideasui-font-mono: 'Geist Mono', ui-monospace, monospace;
--ideasui-font-size-custom: 12px; /* new → text-custom */
--ideasui-tracking-custom: 1px; /* new → tracking-custom */
}Shadows
:root {
--ideasui-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--ideasui-shadow-custom: 0 0 0 1px red; /* new → shadow-custom */
}
.dark,
[data-ideasui-theme='dark'] {
--ideasui-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--ideasui-shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.25);
}Built-in shadows: xs sm md lg xl 2xl inner none
Motion
:root {
--ideasui-duration-custom: 1s; /* new → duration-custom */
--ideasui-easing-custom: ease-in-out; /* new → ease-custom */
/* Override existing */
--ideasui-duration-md: 200ms;
--ideasui-easing-standard: cubic-bezier(0.4, 0, 0.2, 1);
}Built-in durations: xs(75ms) sm(100ms) md(150ms) lg(200ms) xl(300ms) 2xl(500ms) 3xl(700ms) 4xl(1000ms)
Built-in easings: standard accelerate decelerate emphasized linear spring
Opacity, Z-Index & Blur
:root {
--ideasui-opacity-custom: 0.5; /* new → opacity-custom */
--ideasui-z-index-custom: 100; /* new → z-custom */
--ideasui-blur-custom: 10px; /* new → blur-custom */
}Built-in z-index: hide(-1) base(0) raised(1) sticky(100) fixed(200) dropdown(1000) overlay(1100) modal(1200) popover(1300) toast(1400) tooltip(1500)
Tip: Custom CSS variable additions create new Tailwind utilities automatically — no rebuild required. Overrides to existing variables also take effect immediately.
License
MIT
