Casca Docs Home API SSG Themes Graph

Casca Adoption Guide

Casca is a no-JS-first CSS library of charts and interactive data components, designed for server-rendered dashboards. This guide explains how to adopt Casca in your project while understanding its design philosophy and guarantees.

Table of Contents


Design Philosophy

Casca is optimized for server-rendered, no-JS-first dashboards and prioritizes:

  1. Zero global side effects - No :root{color-scheme}, no --lightningcss-* build artifacts, all custom properties use --casca-* prefix
  2. NO-JS architecture - All core features work without JavaScript (pagination, interactivity, theming)
  3. Minimal, composable primitives - Small, focused components that work together
  4. Predictable theming via CSS custom properties - Easy to override, hard to break

If your project shares these values, Casca is a great fit. If you need heavy JS interactivity or complex animations, consider a different library.


Which Build Should I Use?

Casca ships one CSS artifact: dist/casca.css. It contains every primitive plus the four-mood theme picker (Solar base + Cyber/Lunar/Arcade picker-scoped overlays).

dist/casca.css (The one bundle)

<link rel="stylesheet" href="casca.css">

This is the recommended starting point for everyone. It is contract-clean (no :root{color-scheme}, no globals) and gives you every chart, every interaction, every layout shell, and the four-mood picker in one link tag.

Tree-shake recipe (subset users)

If you need a curated subset, write your own entry CSS with explicit @import statements for the domain aggregators you want:

/* my-casca.css -- charts-only entry */
@layer casca.design-tokens, casca.tokens, casca.base, casca.charts;

@import "@skellvin/casca-css/src/core/_index.css";    /* required base */
@import "@skellvin/casca-css/src/charts/_index.css";  /* all 18 chart primitives */

Bundle with lightningcss:

lightningcss --bundle --minify \
  --targets 'chrome 95, firefox 95, safari 15' \
  --output-file my-casca.css \
  my-casca.css

Domain aggregators:

DomainImport pathContains
Core (required)src/core/_index.cssDesign tokens, base primitives, accessibility, prose, keyboard shortcuts
Chartssrc/charts/_index.cssAll 18 chart primitives (axis, bar, line, area, pie, progress, stat, table, analytics, heatmap, scatter, waterfall, radar, candlestick, slot-grid, range, date, color)
Interactionssrc/interactions/_index.cssNo-JS form-aware primitives (toggle, switch, disclosure, filter, segment, modal)
Layoutsrc/layout/_index.cssPage/dashboard shell (card, card-grid, toolbar, anchor-nav, site-header/footer, theme-picker, hero)
Themessrc/themes/_index.cssAll four mood overlays (for tree-shake consumers; not imported by dist/casca.css)

Core MUST be imported first (it defines --casca-* variables and the .casca container). All other domains depend on core.

// package exports
import "@skellvin/casca";       // dist/casca.css (the one bundle)
import "@skellvin/casca/live";  // dist/casca-live.js (opt-in live layer)
import "@skellvin/casca/src/*"; // src/* domain aggregators for tree-shaking

Overriding the mood tokens on casca.css

casca.css carries Solar as the unscoped base plus Cyber, Lunar, and Arcade as picker-scoped overlays. All of those mood values live in the casca.themes cascade layer (the last Casca layer), which makes it easy to override two ways:

2. Bring your own palette. Define your own --casca-* values in an unlayered rule. Unlayered styles beat every @layer, so they win over the bundled moods with no !important:

<link rel="stylesheet" href="casca.css">
<style>
  :root {
    --casca-color-1: #6741d9;   /* your brand accent */
    --casca-color-2: #0ca678;
    /* ...any other --casca-* token you want to remap... */
  }
</style>

You can also set a variable inline on a single .casca block (style="--casca-color-1: #6741d9") to reskin just that one chart.

Theming from scratch? Use the tree-shake recipe with src/core/_index.css (no bundled mood layer to fight) and define your --casca-* tokens once. It is cleaner than overriding casca.css, especially around dark mode and picker-scoped mood changes.


Contract Guarantees

Casca enforces a strict CSS contract via automated linting:

What Casca Guarantees

No unscoped global selectors - All styles are scoped to .casca or child classes ✅ No :root{color-scheme} pollution - Themes use prefers-color-scheme media queries instead ✅ All :root variables use --casca-* prefix - No naming conflicts with host styles ✅ No build-injected globals - No --lightningcss-* or other processor artifacts ✅ No JavaScript required - All features work with pure HTML+CSS

What Casca Does NOT Guarantee

Backwards compatibility with ancient browsers - Requires modern CSS (see Compatibility) ❌ Framework-specific integrations - Pure CSS; you handle framework bindings ❌ Interactive charts without server round-trips - Use forms/links; add JS if needed

Enforced by Linter

The contract is automatically verified:

make lint       # Lints dist/casca.css against the Casca contract

make lint must pass before any release.


Generalization Policy

Casca is no-JS-first, and it is meant to be safely adoptable by any host app. This policy says what the project will add, what it will refuse, and what stays fixed - so growing the audience never erodes the core guarantees.

Stays true no matter what:

Safe to add (opt-in, never required):

Refused (would break the contract):

Every new primitive or public token is API: document it, add an example, and keep all three lint commands green.


Bring Your Own Theme

If you're using Casca, you can provide CSS custom properties for theming.

Minimal Theme Bridge Example

/* Map Casca tokens to your design system */
.casca {
  /* Brand colors */
  --casca-color-1: var(--brand-primary, #228be6);
  --casca-color-2: var(--brand-secondary, #12b886);
  --casca-color-3: var(--brand-accent, #fd7e14);
  --casca-color-4: var(--brand-highlight, #e64980);
  --casca-color-5: var(--success-color, #40c057);
  --casca-color-6: var(--info-color, #845ef7);
  --casca-color-7: var(--warning-color, #fab005);
  --casca-color-8: var(--danger-color, #fa5252);

  /* Grayscale (light mode) */
  --casca-gray-0: #ffffff;
  --casca-gray-1: #f8f9fa;
  --casca-gray-2: #e9ecef;
  --casca-gray-3: #dee2e6;
  --casca-gray-4: #ced4da;
  --casca-gray-5: #adb5bd;
  --casca-gray-6: #6c757d;
  --casca-gray-7: #495057;
  --casca-gray-8: #343a40;
  --casca-gray-9: #212529;

  /* Optional: spacing/sizing if you want to override defaults */
  --casca-size-1: 0.25rem;
  --casca-size-2: 0.5rem;
  --casca-size-3: 0.75rem;
  --casca-size-4: 1rem;
  --casca-size-5: 1.5rem;
  --casca-size-6: 2rem;
}

/* Dark mode overrides */
@media (prefers-color-scheme: dark) {
  .casca {
    --casca-gray-0: #1a1a1a;
    --casca-gray-1: #2c2c2c;
    --casca-gray-2: #3a3a3a;
    --casca-gray-3: #4a4a4a;
    --casca-gray-4: #5a5a5a;
    --casca-gray-5: #6a6a6a;
    --casca-gray-6: #a0a0a0;
    --casca-gray-7: #c0c0c0;
    --casca-gray-8: #e0e0e0;
    --casca-gray-9: #f5f5f5;
  }
}

See src/themes/default.css for the complete default theme as a reference.

Slot Grid (booking / scheduling UIs)

The form-aware slot grid (casca-slot-grid) is a native radio group, so it works from casca.css with no theme dependency - it falls back to the casca grayscale + --casca-color-1 and is dark-mode aware out of the box. To match it to your design system, map its --casca-slot-* tokens (all optional; sensible defaults are built in):

/* Map the slot grid to your booking UI */
.casca-slot-grid {
  /* Selected slot = your primary action color */
  --casca-slot-selected-bg: var(--brand-primary, #228be6);
  --casca-slot-selected-color: #ffffff;
  --casca-slot-selected-border: var(--brand-primary, #228be6);

  /* Available + hover surfaces */
  --casca-slot-bg: var(--surface-2, #f8f9fa);
  --casca-slot-border: var(--border-subtle, #dee2e6);
  --casca-slot-hover-bg: var(--surface-3, #e9ecef);

  /* Taken / disabled */
  --casca-slot-taken-color: var(--text-muted, #adb5bd);

  /* Layout knobs */
  --casca-slot-cols: 5;        /* or set inline per grid via style="" */
  --casca-slot-min-size: 2.75rem;  /* >= 44px touch target */
}

Because each slot is a real <input type="radio">, the chosen slot is submitted with a normal <form> POST and is keyboard accessible without JavaScript. Always re-validate the submitted slot server-side; disabled (taken) slots are never submitted by the browser, but never trust that alone.

See site/pages/controls/slot-grid.html and site/assets/integrations/go-templates/slot-grid.tmpl.


Framework Integration

Casca is pure CSS and works with any framework that renders HTML. See docs/integrations/ for specific examples:

General Integration Pattern

  1. Install Casca:

    npm install @skellvin/casca
    # or
    bun add @skellvin/casca
    
  2. Import CSS (framework-specific syntax):

    // Astro, Next.js, etc.
    import '@skellvin/casca';
    
  3. Render semantic HTML:

    <figure class="casca casca-figure">
      <figcaption class="casca-title">Sales</figcaption>
      <table class="casca-data">
        <caption>Sales</caption>
        <thead><tr><th scope="col">Period</th><th scope="col">Value</th></tr></thead>
        <tbody><tr><th scope="row">Latest</th><td>75</td></tr></tbody>
      </table>
      <div class="casca-bar" aria-hidden="true">
        <div class="casca-bar-group">
          <div class="casca-bar-item">
            <div class="casca-bar-value"
                 style="--value: 75%; --color: var(--casca-color-1)"></div>
          </div>
        </div>
      </div>
    </figure>
    
  4. (Optional) Add theme bridge to map Casca tokens to your design system


When NOT to Use Casca

Casca is not a good fit if you need:

❌ Heavy JavaScript Interactivity

❌ Real-time Animated Charts

❌ Very Complex Visualizations

❌ Legacy Browser Support

✅ Use Casca When You Need:


Getting Help


License

See LICENSE file in project root.

Page graph for Casca Adoption Guide: 5 pages, 7 links within 1 hop.
Page graph for Casca Adoption GuideEgo-centric graph showing Casca Adoption Guide and connected published markdown pages within 1 hop.CascaCasca APIReferenceBrowserCompatibilityIntegrationGuide (serv...Casca AdoptionGuide