Tailwind CSS + shadcn/ui — GE Design System¶
OWNER: alexander ALSO_USED_BY: floris, floor LAST_VERIFIED: 2026-03-26 GE_STACK_VERSION: tailwindcss ^4, shadcn ^3.8.4, class-variance-authority ^0.7.1, clsx ^2.1.1, tailwind-merge ^3.4.0, radix-ui ^1.4.3
Overview¶
Tailwind CSS v4 and shadcn/ui form the visual foundation of every GE client project.
Tailwind v4 uses CSS-first configuration via @theme — no tailwind.config.js.
shadcn/ui provides owned component source code built on Radix primitives.
Agents use this page to understand how GE structures styling and UI components.
GE Design System Approach¶
CHECK: Every GE project starts from the same design token base.
IF: A client project needs custom branding.
THEN: Override semantic tokens in :root — never modify base tokens in @theme.
CHECK: shadcn/ui components live in components/ui/.
IF: You need a project-specific variant.
THEN: Create a wrapper in components/ that composes the ui/ primitive.
THEN: Never edit components/ui/ files directly — they are the upgrade-safe base.
Tailwind v4 Configuration¶
Tailwind v4 is CSS-first. The entire config lives in your main CSS file.
CHECK: The project uses @import "tailwindcss" as the single entry point.
IF: You see @tailwind base, @tailwind components, @tailwind utilities.
THEN: You are looking at v3 syntax — migrate immediately.
CHECK: Design tokens are defined in @theme { } blocks.
IF: You need a custom color, spacing value, or font.
THEN: Add it inside @theme — Tailwind auto-generates utilities from it.
CHECK: Content detection is automatic in v4.
IF: Files in .gitignore are being scanned.
THEN: This is a bug — v4 respects .gitignore by default.
ANTI_PATTERN: Creating a tailwind.config.js file in a v4 project.
FIX: All configuration belongs in CSS via @theme and @import.
ANTI_PATTERN: Using postcss-import or autoprefixer alongside v4.
FIX: Tailwind v4 handles imports and vendor prefixing internally.
shadcn/ui as Component Base¶
shadcn/ui is not a dependency — it is copied source code you own. GE uses shadcn as the starting point, then customizes per project.
CHECK: Components are installed via npx shadcn@latest add <component>.
IF: You need a component that shadcn provides.
THEN: Install it first, then customize — never build from scratch.
CHECK: All shadcn components use Radix UI primitives underneath. IF: You need keyboard navigation, focus management, or ARIA. THEN: Radix handles it — do not re-implement accessibility.
GE Component Folder Structure¶
components/
ui/ # Raw shadcn components (upgrade-safe, minimal edits)
primitives/ # Lightly modified base components (GE defaults applied)
blocks/ # Product-level compositions (cards, dashboards, forms)
layout/ # Shell, sidebar, nav, footer
CHECK: A new component is being created.
IF: It is a generic UI element (button, input, dialog).
THEN: It belongs in components/ui/ via shadcn install.
IF: It is a GE-specific composition of multiple primitives.
THEN: It belongs in components/blocks/.
Key Utilities¶
GE uses three utilities together for className management:
- clsx — conditional class joining
- tailwind-merge — deduplicates conflicting Tailwind classes
- cn() — the combined helper (clsx + tailwind-merge)
CHECK: Every component that accepts className as a prop.
THEN: Use cn() to merge — never string concatenation.
import { cn } from "@/lib/utils"
export function Card({ className, ...props }) {
return <div className={cn("rounded-lg border bg-card p-6", className)} {...props} />
}
Performance Notes¶
Tailwind v4's Oxide engine (Rust-based) delivers: - Full builds: under 100ms (was 3.5s in v3) - Incremental builds: single-digit milliseconds - No purge configuration needed — automatic tree-shaking
Cross-References¶
READ_ALSO: wiki/docs/stack/tailwind-shadcn/design-tokens.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/component-patterns.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/responsive.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/pitfalls.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/checklist.md READ_ALSO: wiki/docs/stack/nextjs/index.md