EXSA Docs
v1.0

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 concept_d/ folder into your project
your-project/
  ├── style.css          ← core: tokens, reset, layout, elements
  ├── components/        ← 49 component CSS files
  ├── components.js       ← interactive behaviors
  └── themes/            ← 17 theme files

2. Link the core

<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="themes/breeze.css">
That's it. The core (style.css) is 11.8 KB and includes tokens, reset, layout utilities, and classless element styles. The theme file overrides ~12 color tokens. 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="style.css">
  <link rel="stylesheet" href="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>
    <section>
      <h2>Welcome</h2>
      <p>This paragraph gets automatic margin and typography.</p>
      <p><code>Inline code</code> gets accent background styling.</p>
      <aside>This becomes a card — border, shadow, responsive padding.</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. All of this happens without a single class — it's the classless engine working.

Adding Components

Each component is a single CSS file in the components/ folder. Link only what you need.

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

<!-- For interactive components, also include the JS -->
<script src="components.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>
  </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 5-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 outside all layers, so they always win.

@layer exsa.tokens, exsa.reset, exsa.layout, exsa.elements, exsa.components;
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

36 CSS custom properties defined on :root. Colors (--color-link, --color-bg), spacing (--gap, --gap-sm), typography (--font-family, --line-height), 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: 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 3: Layout

65+ utility classes for flex, grid, gap, containers, positioning, text alignment, overflow, and responsive breakpoints. Always on. No prefix.

Layer 4: Elements

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

Layer 5: Components

49 self-contained components — each is one CSS file. Link only what you need. All use :where() for zero specificity.

Tokens — The Source of Truth

Every visual decision in EXSA flows from 36 CSS custom properties. 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 all 36 tokens in a structured JSON format — 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 container rules — <section>, <header>, <main>, <footer>. If you add any class to these elements, the framework's layout rules step aside.

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

<!-- Framework stays out — you're in control -->
<section class="my-custom-layout">
  <!-- display, flex-wrap, justify-content NOT set by EXSA -->
  <!-- But <aside> cards inside STILL get styled -->
</section>
Child styles are never guarded. Even inside a classed <section>, child <aside> elements still get card styling. <nav> children (<ul>, <li>) always get dropdown behavior. Only the container's layout properties are guarded.

How Themes Work

A theme is a CSS file that overrides ~12 color tokens on :root. Because themes are loaded outside the @layer cascade (unlayered styles always win), theme values always override the default tokens.

/* themes/night.css — a complete theme in ~12 lines */
:root {
  --color-bg: #1c1f2e;
  --color-bg-secondary: #2a2d3a;
  --color-text: #e2e4e9;
  --color-text-secondary: #9498a4;
  --color-link: #60a5fa;
  --color-secondary: #c084fc;
  --color-accent: #60a5fa18;
  --color-secondary-accent: #c084fc18;
  --color-shadow: #00000040;
  --color-scrollbar: #3a3d4a;
  --color-table: #60a5fa;
}

Swap themes by changing one <link> href. All 49 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, --color-table
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 default tokens include a @media (prefers-color-scheme: dark) block with dark defaults. If you don't load a theme file, the framework automatically switches based on OS preference.

2. Dark-first themes

Themes like night, volt, ember, abyss, shadow, ink are dark by default. They set dark tokens at :root level — no media query needed.

3. Runtime switching (JavaScript)

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

Layout Utilities

65+ utility classes in the layout 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

Responsive Helpers

Three breakpoints. Classes activate at or below the specified width:

BreakpointWidthExamples
sm:≤ 575px.sm\:flex-col .sm\:grid-cols-1
md:≥ 768px.md\:col-3 .md\:grid-cols-3
lg:≥ 1024px.lg\:col-4 .lg\:grid-cols-4

Component Model

Every EXSA component follows the same pattern:

/* What a component looks like internally */
:where(.card) {
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
:where(.card--hoverable:hover) {
  box-shadow: var(--box-shadow) var(--color-shadow);
}

BEM Naming Convention

EXSA uses BEM (Block, Element, Modifier) for all component classes. It's the simplest way to guarantee zero naming collisions across 49 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, alerts, dropdownsStyle variants
--vertical / --horizontalStepper, data-list, separatorOrientation
--active / --disabled / --loadingStateful componentsCurrent state
Creating your own component? Follow the same conventions: one CSS file, :where() for zero specificity, var(--token) for all values, BEM naming. Your component will feel native to EXSA and theme-switch automatically.

JavaScript Behaviors

components.js provides interactive behavior for 29 components. It's class-driven — no hardcoded IDs, no configuration objects. It scans the DOM for component classes and initializes them automatically.

Components that need JS

ComponentWhat JS doesLines
DropdownToggle open/close, outside click dismiss~15
ModalOpen/close, backdrop, Escape, focus trap~20
SlideshowAuto-advance, arrows, dots, pause on hover~30
TabsPanel toggling, active state~15
ToastCreate, auto-dismiss, stack~15
LightboxOpen/close, prev/next, keyboard nav~25
Context MenuRight-click trigger, position clamping~20
PopoverClick trigger, outside/Escape close~15
TopbarScroll shadow, mobile toggle, dropdowns~25
Music PlayerPlay/pause toggle, time tracking~20
And 19 moreCookie bar, rating, stepper, drawer, color picker, date picker, password toggle, range slider, theme switcher, RTL toggle, back-to-top, video gallery, resizer, sidebar, form validation, donut chart...~10-20 each
Pure CSS components need no JS: Accordion, Toggle, Checkbox, Radio, Tooltip, Spinner, Skeleton, Progress Bars, Bar Chart, Donut Chart, Separator, Breadcrumbs — all work with zero JavaScript.

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 exsa.bundle.css + bundle.js
  4. Replace all individual <link> tags with one
<!-- Development: individual files -->
<link href="style.css">
<link href="themes/breeze.css">
<link href="components/card.css">
<link href="components/modal.css">

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

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
160 KB11.8 KB core + components~13x 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.