EXSA
Generate custom CSS

Documentation

Everything you need to build with EXSA. Start with the 5-minute quick start, then dive into the concepts that make this framework different.

Getting Started

EXSA has zero dependencies. No npm, no webpack, no build step. It works with any server that serves static files — Apache, nginx, PHP, Python, Node, Caddy, or just opening .html files directly.

1. Download or clone

# Option A: Copy the dist/ folder into your project
your-project/
  +-- dist/exsa.css        ? core: tokens, reset, utilities, elements
  +-- dist/exsa.fluid.css  ? optional fluid tokens + density profiles
  +-- dist/components/     ? 68 components (+ icons.css)
  +-- dist/js/             ? 37 interactive behaviors + exsa-core.js
  +-- dist/themes/         ? 20 themes + 1 blank custom starter
  +-- dist/layouts/        ? general, dashboard, store
  +-- dist/templates/      ? fullpage + onepage starter kits

# Option B: Git clone
git clone https://github.com/Saif-Almarri/exsa.git
# Then copy the dist/ folder into your project

2. Link the core

<link rel="stylesheet" href="dist/exsa.css">
<link rel="stylesheet" href="dist/themes/breeze.css">
That's it. The core (exsa.css) is 32.4 KB (7.6 KB gzipped) and includes tokens, reset, utilities, classless element styles, and a built-in default theme. A theme file is optional — it overrides ~20 color tokens when you want your own palette. You're ready to build.

Your First Page

Create an index.html with body class="exsa" to enable classless element styling — HTML elements automatically get typography, spacing, and link styling without writing a single CSS rule.

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="dist/exsa.css">
  <link rel="stylesheet" href="dist/themes/breeze.css">
</head>
<body class="exsa">

  <header>
    <h1>My Site</h1>
    <nav>
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <h2>Welcome</h2>
    <p>This paragraph gets automatic margin and typography.</p>
    <p><code>Inline code</code> gets accent background styling.</p>

    <section>
      <aside>This becomes a card — border, shadow, responsive padding.</aside>
      <aside>A second card. The section lays its direct children out in a row.</aside>
    </section>
  </main>

  <footer>
    <p>&copy; 2026</p>
  </footer>

</body>
</html>

The <header> is centered and padded. The <nav> is a flex row. <aside> elements inside <section> become cards. A classless <section> lays its direct children out in a flex row — that's why the two cards sit side by side, and why headings and paragraphs belong in <main> (or an <article>), where they stack in normal block flow. A plain <table> gets borders and header styling. A plain <button> gets padding, border, and hover feedback. All of this happens without a single class — it's the classless engine working. (Want a normal block-flow <section>? Add any class to it — see Guarded Styles.)

Adding Components

Three ways to add components:

  1. Ready-made bundles — link exsa.bundle.css + exsa.js and every component works. Fastest path.
  2. Use the Bundle Generator — select only the components you use, pick a theme, and download minified CSS + JS with exactly your selection baked in.
  3. Download individual files — each component is a single CSS file in dist/components/ with its behavior in dist/js/. Link only what you need.

Method 1: Ready-made bundles

<!-- One CSS file: EXSA core + all 68 components + icons + Breeze theme -->
<link rel="stylesheet" href="dist/exsa.bundle.css">

<!-- One JS file: exsa-core + all 37 behaviors -->
<script src="dist/exsa.js"></script>

Two tags and everything works — no per-component links, no per-behavior scripts. The bundle ships with the Breeze theme baked in and includes the icons library. Want a different theme? Link dist/themes/<name>.css after the bundle (the theme layer wins), or generate a custom bundle (Method 2). Not included: exsa.fluid.css, dist/layouts/, and dist/templates/ — link those separately when you use them.

Method 2: Bundle Generator

Go to generator.php, check the components you want, pick a theme (or "none" to bring your own), and download the CSS bundle + JS bundle — one click each. Two files, zero unused styles.

<!-- Generator output: EXSA core + selected components + theme -->
<link rel="stylesheet" href="dist/exsa.bundle.css">
<script src="dist/exsa.js"></script>

Method 3: Individual files

<!-- Add these after exsa.css -->
<link rel="stylesheet" href="dist/components/buttons.css">
<link rel="stylesheet" href="dist/components/card.css">
<link rel="stylesheet" href="dist/components/modal.css">
<link rel="stylesheet" href="dist/components/tabs.css">

<!-- For interactive components, link each behavior you use -->
<script src="dist/js/exsa-core.js"></script>
<script src="dist/js/modal.js"></script>
<script src="dist/js/tabs.js"></script>

Then use them in your HTML:

<button class="btn btn--primary">Click Me</button>

<div class="card">
  <div class="card__body">
    <h3 class="card__title">Card Title</h3>
    <p class="card__text">Card description text.</p>
  </div>
</div>

<div class="modal" id="my-modal">...</div>
Pro tip: Use the Generator to select components visually, then download a single exsa.bundle.css with everything you picked — no unused styles.

The 9-Layer Cascade

EXSA uses CSS @layer to enforce an explicit cascade order. Each layer has one job. Layers lower in the list override layers higher — and themes sit directly above tokens, so theme overrides always win.

@layer exsa.tokens, exsa.themes, exsa.fluid, exsa.reset, exsa.utilities, exsa.elements, exsa.components, exsa.layouts, exsa.overrides;
Why layers matter: Without @layer, specificity determines which rule wins — a class from a component could accidentally override a token. With layers, the cascade order is explicit and predictable regardless of specificity.

Layer 1: Tokens

82 design tokens defined on :root (64 documented in tokens.json). Colors, spacing, typography, breakpoints, z-index scale, behavioral factors (--space-factor, --radius-factor, --font-factor, --motion-factor), shadows, border radius, hover brightness. Everything else references these.

Override any token in your own stylesheet or swap the theme file — all components update automatically.

Layer 2: Themes

One CSS file per theme — ~20 color-token overrides. Swap one <link> href and the whole site recolors. Themes sit above tokens in the cascade, so their overrides always win.

Layer 3: Fluid

The optional dist/exsa.fluid.cssclamp()-scaled spacing, type, and radius plus data-profile density factors. One file, no breakpoints. The prebuilt exsa.bundle.css does not include it — link it separately when you want fluid scaling.

Layer 4: Reset

Box-sizing, focus rings, scrollbar styling, RTL support, reduced motion, forced-colors mode, skip links, body defaults. Applies globally — no opt-in needed.

Layer 5: Utilities

89 utility classes (plus responsive variants) for flex, grid, gap, containers, positioning, text alignment, overflow, and responsive breakpoints. Always on. No prefix.

Layer 6: Elements

Classless HTML styling — activated by body class="exsa". Styles <p>, <a>, <code>, <pre>, <nav>, <section>, <aside>, <table>, <form>, <button>, <blockquote>, <dialog>, and more. Uses :where() for zero specificity.

Layer 7: Components

68 self-contained components — each is one CSS file. Link only what you need. BEM naming prevents collisions — no build tool required.

Layer 8: Layouts

Drop-in page shells (general, dashboard, store) — topbar, sidebar, and content zones wired to the layout tokens.

Layer 9: Overrides

The u-* escape hatch — single-property utilities that always beat components and layouts. Your own unlayered CSS still beats them.

Tokens — The Source of Truth

Every visual decision in EXSA flows from 82 design tokens in :root (64 documented in tokens.json). Change a token — every component, every element, every utility that references it updates instantly.

/* Key tokens you'll override most often */
--color-bg: #fff;              /* page background */
--color-text: #000;            /* body text */
--color-link: #118bee;          /* links, primary actions, focus ring */
--color-secondary: #920de9;     /* accent, visited links */
--color-bg-secondary: #e9e9e9;  /* cards, stripes, borders */
--border-radius: 5px;           /* all rounded corners */
--box-shadow: 2px 2px 10px;     /* shadow offset + blur */
--font-family: ...;             /* system font stack */

/* Spacing scale — 7 steps */
--gap-xs: 0.25rem;  --gap-sm: 0.5rem;  --gap-md: 0.75rem;
--gap: 1rem;       --gap-lg: 1.5rem; --gap-xl: 2rem;
--gap-2xl: 3rem;

/* Semantic colors */
--color-success: #16a34a;       /* green */
--color-danger: #dc2626;        /* red */
--color-warning: #d97706;       /* amber */

Full token reference: Cheatsheet → Tokens

Design tool export: tokens.json exports the token catalog in structured JSON — 64 core tokens (of the 82 in exsa.css), the z-index scale, and component/layout tokens — import into Figma (via Tokens Studio), JavaScript, or Tailwind config. Light and dark values included for every color token.

Classless Elements

Add class="exsa" to <body> and semantic HTML elements get automatic styling:

All classless styles use :where() — specificity of zero. A single class from your own CSS always wins.

Guarded Styles

EXSA uses :not([class]) on structural element rules — <section>, <header>, <main>, <footer>, <nav>, <table>, <form>, <button>, <blockquote>, <dialog>. If you add any class to these elements, EXSA's styling steps aside completely.

<!-- EXSA styles this: flex-wrap, centered cards -->
<section>
  <aside>Card 1</aside>
  <aside>Card 2</aside>
</section>

<!-- EXSA styles this: bordered, header bg, cell padding -->
<table>...</table>

<!-- EXSA stays out — you're in control -->
<section class="my-custom-layout">
  <table class="data-grid">...</table>
</section>
The rule is simple: add any class to an element and EXSA steps aside. <table class="data-grid"> — no borders, no header bg. <button class="special"> — no padding, no border, no hover. You get a clean slate. Then add the component file (table.css, buttons.css) and use BEM classes for the upgraded experience.
Container query containment: Classless <section> elements use container-type: inline-size for responsive card layouts. This establishes a new containing block — any position: absolute or position: fixed children position relative to the section, not the viewport. If this causes unexpected positioning, simply add any class to the <section> — EXSA will step aside and remove the container query.

How Themes Work

A theme is a CSS file that overrides ~20 color tokens on :root. Themes live in @layer exsa.themes — directly above tokens in the cascade — so their overrides always beat the default token values.

/* themes/night.css — a complete theme in ~20 lines */
@layer exsa.themes {
:root {
  color-scheme: light dark;
  --color-bg: light-dark(#f8fafc, #0f1117);
  --color-bg-secondary: light-dark(#e2e8f0, #1c1f2e);
  --color-text: light-dark(#0f172a, #e2e8f0);
  --color-link: light-dark(#2563eb, #60a5fa);
  --color-secondary: light-dark(#7c3aed, #c084fc);
  --color-accent: light-dark(#2563eb10, #60a5fa12);
  --color-secondary-accent: light-dark(#7c3aed0d, #c084fc12);
  --color-success: light-dark(#16a34a, #22c55e);
  --color-danger: light-dark(#dc2626, #ef4444);
  --color-warning: light-dark(#d97706, #f59e0b);
  --color-scrollbar: light-dark(#94a3b8, #334155);
  --border-radius: 6px;
}
}

Swap themes by changing one <link> href. All 68 components, all element styles, all utilities — everything recolors instantly. No rebuild.

Creating a Custom Theme

Copy any existing theme file (start with breeze.css for light, night.css for dark) and override these tokens:

  1. Background pair: --color-bg + --color-bg-secondary
  2. Text pair: --color-text + --color-text-secondary
  3. Brand colors: --color-link + --color-secondary
  4. Accent tints: --color-accent + --color-secondary-accent (use 8-digit hex with alpha)
  5. Semantic colors: --color-success, --color-danger, --color-warning (and their -hover variants)
  6. Chrome: --color-scrollbar, --color-shadow
8-digit hex for accents: #118bee15 means #118bee at ~8% opacity. The last two digits are hex alpha — 00 (transparent) to FF (opaque). Use this for subtle tint backgrounds.

Dark Mode & System Preference

EXSA supports three approaches to dark mode:

1. System preference (built-in)

The core tokens use CSS light-dark() with color-scheme: light dark — dark values ship in the same definition. Load no theme file and the framework follows OS preference automatically.

2. Forced mode

Every theme ships both light and dark values via light-dark(). Force either mode regardless of OS preference with one attribute:

<html data-theme-mode="dark">
<html data-theme-mode="light">

3. Runtime switching (JavaScript)

// Switch theme programmatically
document.getElementById('theme-stylesheet').href = 'dist/themes/night.css';

Layout Utilities

89 base utility classes (plus responsive variants) in the utilities layer. Always on, no prefix, no breakpoint memorization. Full reference: Cheatsheet → Layout.

Containers

.container       /* max-width: 1080px, centered, padded */
.container-sm    /* max-width: 800px */
.container-full  /* width: 100% */

Flex

.flex .flex-col .flex-wrap .flex-1
.justify-center .justify-between .items-center
.gap-sm .gap .gap-lg .gap-xl

Grid

.grid .grid-cols-3 .grid-auto-fit

Position & Sizing

.relative .absolute .fixed .sticky .inset-0
.w-full .h-full .overflow-hidden .overflow-auto
.text-center .text-left .text-right

Typography

20 utility classes for font sizing, weight, family, and transforms — all driven by --font-* tokens. Swap a token, every element using these classes updates instantly.

Override utilities (u-*)

Unprefixed utilities are structural and lose to components. When you deliberately need to adjust a component — card u-text-center, btn u-w-full — the u-* classes in the top exsa.overrides layer always win over components and layouts. Your own unlayered CSS still beats them.

.u-text-center .u-text-end .u-flex .u-none
.u-w-full .u-m-0 .u-p-0 .u-mx-auto
.u-gap-0 .u-gap-sm .u-gap .u-gap-lg
.u-radius-0 .u-radius-full
GroupClassesToken
Font sizes.text-xs .text-sm .text-base .text-md .text-lg .text-xl .text-2xl--font-size-* (11px–29px)
Font weights.fw-normal .fw-bold .fw-heavy--font-weight-* (400/700/800)
Font families.font-sans .font-mono .font-heading--font-family / --font-family-heading
Transforms.italic .uppercase .capitalize
Utilities.text-muted .text-start .text-center .text-end--color-text-secondary
<!-- Typography utilities in action -->
<h1 class="text-2xl fw-heavy font-heading">Main Heading</h1>
<p  class="text-base text-muted">Body copy with muted color</p>
<span class="text-sm fw-bold uppercase">small bold caps</span>

Page Layouts

EXSA ships with 3 composable layouts + 2 starter templates — drop-in CSS files that turn semantic HTML zones into complete page shells. Link the one you need, add its classes to <body>, and structure your HTML with the documented zones.

The Layouts & Templates

LayoutFileUse For
Generaldist/layouts/general.cssDocumentation sites, reference pages — topbar + sidebar + content + footer
Blogdist/layouts/general.cssArticles, prose — blog mode (blog--prose, blog--has-toc) merged into the general layout
Dashboarddist/layouts/dashboard.cssAdmin panels, web apps — fixed sidebar, scrollable content
Storedist/layouts/store.cssEcommerce — announcement bar, cart topbar, filter sidebar, product grid
Fullpagedist/templates/fullpage/Starter template: single-viewport landing — media/panned backdrop, centered brand, social rings, pure-CSS panels, copyright
Onepagedist/templates/onepage/Starter template: multi-section marketing page — photo hero, nav dropdowns, banner, carousel, features grid, dark footer

How They Work

All five layouts follow the same pattern:

  1. Link the layout CSS after exsa.css and your theme.
  2. Add the layout's body classes to <body>.
  3. Structure your HTML with the documented zone elements.

Layouts use the topbar component's --topbar-height variable — swap topbar--sm for topbar--xl and body padding updates automatically. Fixed zones across layouts and components share one token-driven z-index scale (--z-topbar, --z-modal, --z-layout-aside…), so you can retune stacking from a single place in your theme.

Browse all five layouts: Visit the Layouts page for live previews, body class tables, CSS token references, and copy-paste starter templates for each layout.

Responsive Helpers

Five breakpoints. Classes activate at or above the specified width (except sm: which applies below):

BreakpointWidthTargetExamples
sm:= 575pxPhones.sm\:flex-col .sm\:grid-cols-1
md:= 768pxTablets.md\:col-3 .md\:grid-cols-3
lg:= 1024pxLaptops.lg\:col-4 .lg\:grid-cols-4
xl:= 1280pxDesktops.xl\:col-5 .xl\:grid-cols-5
xxl:= 1440pxLarge Desktops.xxl\:col-5 .xxl\:grid-cols-5

Breakpoint Tokens & JS

All 5 breakpoints are CSS tokens (--bp-sm through --bp-xxl) on :root. They can't be used directly in CSS @media queries today — that needs @custom-media (draft spec). But they power EXSA.bp for JS-driven responsive logic, keeping breakpoints as a single source of truth:

// Tablet and up?
if (EXSA.bp.up('md').matches) {
  // 768px+
}

// Mobile only — reactive
EXSA.bp.down('sm').addEventListener('change', function(e) {
  if (e.matches) { /* <= 575px */ }
});

// Raw pixel value
var w = EXSA.bp.val('lg'); // "1024px"
Change a breakpoint once, everything follows. Override --bp-md in your theme and EXSA.bp.up('md') reads the new value automatically. (The responsive utility classes inside exsa.css use fixed values — CSS can't read custom properties in media queries without @custom-media, a draft spec.) No magic numbers. One source of truth for JS.

Fluid Tokens & Profiles

EXSA offers an optional, per-project fluid-first approach to responsive design — ideal for content sites and large screens. Instead of breakpoints and responsive classes, tokens themselves scale smoothly with viewport width using clamp(). Link one file and every component becomes fluid and the data-profile density attributes activate. Without this file, tokens stay static and data-profile has no effect.

Setup

<!-- Core -->
<link rel="stylesheet" href="dist/exsa.css">
<link rel="stylesheet" href="dist/themes/breeze.css">

<!-- Fluid tokens + profiles — optional, link after core -->
<link rel="stylesheet" href="dist/exsa.fluid.css">

What Gets Fluid

Token GroupExampleEffect
Spacing (7 tokens)--gap: clamp(0.75rem, 0.6rem + 0.5vw, 1.25rem)Gaps, padding, margins scale with viewport
Typography (7 tokens)--font-size-base: clamp(0.82rem, 0.8rem + 0.3vw, 1.05rem)Font sizes scale smoothly — no breakpoint jumps
Shape--border-radius: clamp(4px, 0.3vw, 10px)Corners round proportionally on larger screens
Layout--width-content: clamp(320px, 90%, 1080px)Containers fill available space, capped at max-width

Behavioral Profiles

Add data-profile to <html> to change the density of every component via factor tokens — no class changes, no rebuild. Requires exsa.fluid.css (linked above):

ProfileAttributeSpaceRadiusTypeMotion
Compactdata-profile="compact"0.8×0.85×0.95×0.6×
Comfortable(default — no attribute)
Spaciousdata-profile="spacious"1.3×1.2×1.1×1.4×
<!-- Switch profiles with one attribute change -->
<html data-profile="compact">   <!-- denser dashboards, data-heavy apps -->
<html data-profile="spacious">  <!-- landing pages, marketing, kiosks -->
Fluid for values. Adaptive for layout. Fluid tokens handle spacing, typography, and shape without breakpoints. Profiles change density with one HTML attribute — no class changes. For structural changes — switching from 1 column to 3 columns — use responsive utility classes (.md\:grid-cols-3) or auto-fit/minmax() grids.

Component Model

Every EXSA component follows the same pattern:

/* What a component looks like internally */
.card {
  background: color-mix(in srgb, var(--color-bg) 97%, var(--color-text));
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
.card--hoverable:hover {
  box-shadow: var(--box-shadow);
  transform: translateY(-2px);
}

BEM Naming Convention

EXSA uses BEM (Block, Element, Modifier) for all component classes. It's the simplest way to guarantee zero naming collisions across 68 components — no build tool required.

The three rules

PartPatternExampleMeans
Block.block.cardThe component root
Element.block__element.card__titleA child of the block
Modifier.block--modifier.card--hoverableA variant or state

Why not utility classes? Why not CSS Modules?

ApproachNeeds build step?Naming collisions?Token-friendly?
BEM (EXSA)NoNo — unique prefixesYes — all values are var(--token)
Utility (Tailwind)RequiredNo — atomic classesNo — hardcoded values
CSS ModulesRequiredNo — auto-scopedYes — can use var()
Scoped (Vue/Svelte)Framework-dependentNo — auto-scopedYes — can use var()

Abbreviated modifiers

For common variants, EXSA uses short, memorable modifier names:

ModifierUsed onMeans
--sm / --lg / --xlMost componentsSize variants
--primary / --success / --danger / --warningButtons, badges, alertsSemantic color variants
--outline / --ghost / --soft / --surfaceButtons, dropdownsStyle variants
--vertical / --horizontalStepper, data-list, separatorOrientation
--active / --disabled / --loadingStateful componentsCurrent state
Creating your own component? Follow the same conventions: one CSS file, BEM naming, var(--token) for all values. Your component will feel native to EXSA and theme-switch automatically.

JavaScript Behaviors

Each interactive component has one behavior file in dist/js/modal.js, tabs.js, dropdown.js… 37 behaviors in total. Class-driven — no hardcoded IDs, no configuration objects. Each file scans the DOM for its component classes and initializes them automatically. Load dist/js/exsa-core.js first (focus-trap utilities), then only the behaviors you use.

Components that need JS

ComponentWhat JS doesLines
DropdownToggle open/close, outside click dismiss~37
ModalOpen/close, backdrop, Escape, focus trap~48
SlideshowAuto-advance, arrows, dots, pause on hover~39
TabsPanel toggling, active state~41
ToastCreate, auto-dismiss, stack~31
LightboxOpen/close, prev/next, keyboard nav~63
Context MenuRight-click trigger, position clamping~61
PopoverClick trigger, outside/Escape close~34
TopbarScroll shadow, mobile toggle, dropdowns~71
Music PlayerPlay/pause toggle, time tracking~34
And 27 moreCookie bar, rating, color picker, advanced color picker, date picker, password toggle, range slider, back-to-top, video gallery, resizer, sidebar, accordion, toggle, drawer, carousel, code block, RTL toggle, scroll spy, theme switcher, calendar, chart, command palette, kanban, table sort/filter/select, tags input, transfer list, upload dropzone~20-70 each
Pure CSS components need no JS: Checkbox, Radio, Tooltip, Spinner, Skeleton, Progress Bars, Bar Chart, Donut Chart, Stepper, Form Validation, Separator, Breadcrumbs, Toggle, Accordion — all work with zero JavaScript. (Accordion and Toggle also have optional JS for ARIA enhancements.)

Tree-Shaking & Generator

During development, link individual component CSS files. For production, use the Generator to create a single bundle:

  1. Pick your theme
  2. Select the components you use
  3. Download the CSS bundle + the JS bundle (one click each)
  4. Replace all individual <link> tags with one
<!-- Development: individual files -->
<link href="dist/exsa.css">
<link href="dist/themes/breeze.css">
<link href="dist/components/card.css">
<link href="dist/components/modal.css">

<!-- Production: one file -->
<link href="dist/exsa.bundle.css">

Icons Library

EXSA includes 112 SVG icons — 103 Feather Icons (stroke-based, MIT) + 9 Simple Icons brand logos (CC0). All rendered via CSS masks with currentColor — theme colors apply automatically. Icons inherit the text color of their parent.

Usage

<!-- Basic usage with the .ic base + .ic-{name} -->
<span class="ic ic-search"></span>
<span class="ic ic-heart"></span>

<!-- In buttons -->
<button class="btn btn--primary">
  <span class="ic ic-download"></span> Download
</button>

<!-- With custom size -->
<span class="ic ic-settings" style="width:20px;height:20px"></span>

Setup

Add one stylesheet — it defines the .ic base mask system and maps all 112 icons to their SVG files (the paths are relative, so it works from any location):

<!-- Icon system — one file -->
<link rel="stylesheet" href="dist/components/icons.css">
Browse all 112 icons: Visit the Icons Library page for a searchable gallery with click-to-copy class names, organized by category.

Migrating from Bootstrap

BootstrapEXSANotes
.container.containerSame API
.row / .col-md-6.flex + .col-2 or .grid + .grid-cols-2No row wrapper needed
.btn-primary.btn .btn--primaryBEM naming, more variants
.alert-info.alert .alert--infoAlso has soft/outline/surface styles
.badge.badgeSame API, more colors
.navbar.topbarFixed top, scroll shadow, mobile hamburger
.modal.modalNested dialog with header/body/footer
.spinner-border.spinner3 sizes, pure CSS
~230 KB32.4 KB core (add components — la carte)~7× smaller core

Migrating from Tailwind

EXSA takes the opposite approach: semantic components instead of atomic utilities. Here's how the mental model translates:

TailwindEXSAPhilosophy
flex justify-between items-center gap-4flex justify-between items-center gapLayout utilities are similar — EXSA uses tokens for spacing
bg-white rounded-lg shadow-md p-6 bordercardOne component class replaces 5+ utilities
text-lg font-semibold text-gray-900card__titleSemantic class carries meaning
Edit every class to change themeSwap one theme fileTokens vs hardcoded values
You can still use EXSA's layout utilities like Tailwind. Classes like .flex, .grid, .gap, .text-center give you utility-class convenience. But for recurring UI patterns, EXSA's components eliminate class repetition.