Design System
Cerne v0.1

A complete design system, built from scratch, with zero external dependencies

Cerne is a self-contained CSS + JS framework โ€” no CDNs, no jQuery, no mandatory builds in production. It was designed to serve multiple domains with the same system of tokens and components: admin dashboards, learning environments, management systems, room scheduling and blogs.

ITCSS + CUBE CSS Utility-first + components Native dark mode Accessible by default Zero dependencies
Why Cerne exists

A powerful tool for modern web development

Cerne is at version 0.1 โ€” an entire design system, built from scratch, with a simple purpose: to give anyone a fast, robust and free foundation for taking systems off the page and onto the internet, with no CDN dependency, no license, no vendor lock-in and no paywall. Open source, accessible to everyone, forever.

What already ships in v0.1

  • 40+ production-ready components โ€” app shell, datatable, calendar, charts, chat, video player, modals, advanced forms and much more.
  • 43 complete examples ready to copy: dashboards, e-commerce, streaming, webmail, social network, news portal, LLM chat, smart TV...
  • Zero external dependencies โ€” no jQuery, no CDN, no mandatory build in production. Opens with a double-click on the HTML file.
  • Native dark mode and prefers-reduced-motion/prefers-color-scheme respected automatically.
  • Real RTL via logical properties โ€” not a mirroring hack.
  • WCAG 2.1 AA accessibility by default on every interactive component.
  • Real internationalization โ€” 168 example pages translated into CJK, Arabic, Hindi and Russian, not just the interface.
  • Genuinely modern CSS โ€” container queries, cascade layers, color-mix(), clamp(), density configurable via data-density.

It's a v0.1 by choice, not by limitation: the core is already solid and in real use across the 43 examples above, but the project keeps evolving in public โ€” every new version adds more primitives, more languages, more components, without breaking what already exists.

RV
Ricardo Cezar Volert Curitiba, Paranรก, Brazil

Creator and maintainer of Cerne. The entire framework โ€” tokens, components, the 43 examples and the regional variants โ€” was designed by Ricardo and built in collaboration with AI (Claude, by Anthropic), with the goal of leaving a good, open and free tool for whoever is building the next generation of systems on the web.

Installation

Copy the compiled files from dist/ into your project and reference them directly. No build step is required to consume the framework.

<link rel="stylesheet" href="dist/css/cerne.css">

<!-- At the end of body: classic script (not type="module") to expose window.Cerne -->
<script src="dist/js/cerne.js"></script>

To avoid a "flash" of the wrong theme before the JS loads, include this snippet in the <head>, before the CSS:

<script>
  var t = localStorage.getItem('cerne-theme');
  if (t) document.documentElement.setAttribute('data-theme', t);
</script>

Colors

Primitive 11-shade palettes + a semantic layer (--cerne-color-primary, -hover, -active, -subtle...) that swaps value automatically between the light and dark themes. The values below are read live from the compiled CSS โ€” never out of sync with this documentation.

Spacing

A 4px scale, exposed as --cerne-space-* and as p-*, m-*, gap-* utilities.

Typography

Modular scale (~1.25), default font = system stack (zero network requests). Swap --cerne-font-sans to use your own self-hosted font.

Radius & Shadow

Elevation with distinct recipes for light/dark โ€” dark shadows don't disappear over a dark background.

Radius

Shadow

Grid

Classic .row/.col-* API over CSS Grid, plus .grid-cols-* / .col-span-* utilities with responsive prefixes md:, lg:.

<div class="row">
  <div class="col-12 col-md-4">...</div>
  <div class="col-12 col-md-4">...</div>
  <div class="col-12 col-md-4">...</div>
</div>

App Shell

The core primitive for dashboards: sidebar + topbar + main via grid-template-areas, collapsing to off-canvas below lg. This very page uses .app-shell.

<div class="app-shell" id="app-shell">
  <div class="app-shell__backdrop"></div>
  <aside class="app-shell__sidebar">...</aside>
  <header class="app-shell__topbar">...</header>
  <main class="app-shell__main">...</main>
</div>

Buttons

Solid, outline and ghost variants for every semantic color, plus sizes and a loading state.

<button class="btn btn-primary">Primary</button>
<button class="btn btn-outline-primary">Outline</button>
<button class="btn btn-ghost-primary">Ghost</button>

Forms

Styled native controls, validation via data-cerne-validate (Constraint Validation API) and error messages customizable by attribute.

<form data-cerne-validate novalidate>
  <div class="form-group">
    <label class="form-label" for="email">Email</label>
    <input class="form-control" type="email" id="email" required
      data-error-required="Enter your email.">
    <span class="form-error"></span>
  </div>
</form>

More forms

Floating label, password with strength and visibility, OTP code, clearable search, slider, tags, combobox, selectable cards, segmented selector, drag-and-drop upload and character counter โ€” to cover any flow, from login to checkout.

Strength: โ€”
Arrows to navigate, Enter to select, Esc to close. The searched term appears in <mark>.
0/140
Drag files here or click to choose
<div class="form-floating">
  <input class="form-control" placeholder=" " id="name">
  <label for="name">Full name</label>
</div>

<div class="otp-input" data-cerne-otp>
  <input class="otp-digit"> <input class="otp-digit"> ...
</div>

<div class="tags-input" data-cerne-tags-input>
  <input type="text" placeholder="Add a tag...">
</div>

<div class="segmented" role="tablist" data-cerne-segmented>
  <button type="button" class="segmented-item is-active" role="tab">30 days</button>
  <!-- ... -->
</div>

<div class="file-drop" data-cerne-file-upload data-cerne-file-list="#file-list">
  <input type="file" multiple>
  <span>Drag files here or click to choose</span>
</div>
<div class="file-list" id="file-list"></div>

Cards

Bookings today 24 +12% vs. yesterday
Card title
Card content with example text.

Media

.carousel (one slide at a time, with dots and optional autoplay) and .shelf (a row with horizontal, RTL-aware scroll) โ€” for institutional-portal heroes and streaming-style catalogs, respectively.

Carousel (data-cerne-carousel-autoplay)

Shelf (hover to reveal the arrows)

Illustration of mountains at sunset
Abstract portrait illustration
Illustration of mountains at sunset, in black and white
Abstract portrait illustration
Illustration of mountains at sunset
<div class="carousel" data-cerne-carousel data-cerne-carousel-autoplay="5000">
  <div class="carousel-track">
    <div class="carousel-slide">...</div>
  </div>
  <button data-cerne-carousel-prev>โ€น</button>
  <button data-cerne-carousel-next>โ€บ</button>
  <div class="carousel-dots"></div>
</div>

<div class="shelf" data-cerne-shelf>
  <button data-cerne-shelf-prev>โ€น</button>
  <div class="shelf-track">
    <div class="shelf-item"><img src="poster.jpg" alt="..." /></div>
  </div>
  <button data-cerne-shelf-next>โ€บ</button>
</div>

Video

Cerne.VideoPlayer โ€” progressive enhancement over existing video markup (doesn't impose its own HTML): play/pause, click-to-seek, volume, speed control. It runs on a "simulated clock" when there's no real <video> (as below), or mirrors a native <video> (MP4, HLS via hls.js...) when you pass [data-video-element] โ€” real adaptive-streaming delivery is the implementer's responsibility, outside the scope of a CSS/JS framework.

0:00 / 0:00
<div class="player" id="player" data-duration="196">
  <button data-video-toggle>โ–ถ</button>
  <div class="player-controls">
    <div class="progress" data-video-seek><div class="progress-bar" data-video-fill></div></div>
    <button data-video-mute-toggle>๐Ÿ”Š</button>
    <input type="range" data-video-volume min="0" max="1" step="0.05" value="1">
    <span data-video-time>0:00 / 0:00</span>
    <button data-video-speed="1.5">1.5x</button>
  </div>
</div>

<script>
  new Cerne.VideoPlayer(document.getElementById("player"), { duration: 196 });
</script>

Complete examples: video with WebVTT captions, streaming with "next episode", live: true broadcast and smart TV with D-pad navigation.

Tables & Datatable

.table for static tables; [data-cerne-datatable] adds client-side sorting, search and pagination with zero dependencies.

Name Course Progress
Marina SilvaComputer Networks92%
Diego SouzaDatabases78%
Ana BeatrizAlgorithms65%
Lucas PereiraComputer Networks40%
Juliana MeloOperating Systems88%
Rafael CostaDatabases55%

Editorial content

Columns, highlight boxes, a highlighter mark with explanatory note and a reading-progress bar โ€” for a blog, news portal or any long text inside .prose. Actually, look at the top of the screen: the thin colored bar above the menu is .reading-progress tracking the scroll of this very documentation page.

Boxes (.callout)

Read also
A link to another related article.
Warning or correction highlighted in the middle of the text.
Explanatory note for a term marked with <mark> in the paragraph above โ€” the "glossary"/"AI explains" style used by news portals.

Highlighter mark (<mark data-cerne-reveal="mark">) + glossary box โ€” the highlight color "paints in" from left to right (or the reverse under dir="rtl") as the term enters the screen, instead of appearing fully rendered.

The rapporteur pointed out that the new regulatory framework changes the approval procedure on the floor.

Regulatory framework is the set of rules governing a specific sector, created or changed by law or decree.

Text columns (.columns-2 / .columns-3, inside .prose)

First column: the text flows vertically and wraps into the next column.

Second column: useful for short highlight lists, glossaries or quotes โ€” collapses to 1 column below md.

<p>The new <mark data-cerne-reveal="mark">regulatory framework</mark> changes the approval procedure.</p>
<div class="callout callout-glossary">
  <svg class="callout-icon"><use href="sprite.svg#icon-search"></use></svg>
  <div class="callout-body"><strong>Regulatory framework</strong> is...</div>
</div>

<div class="columns-2"><p>...</p><p>...</p></div>

<div class="reading-progress"><div class="reading-progress-bar"></div></div>

See a complete example in context in the blog post or the news portal article.

Modals & Offcanvas

Side panel

Used for filters, carts or quick details without leaving the page.

Alerts & Toasts

Success
Your booking has been confirmed.
Attention
This time slot is almost full.

Calendar & Scheduling

A weekly time-slot grid for room booking โ€” see the complete example in Scheduling.

Confirmed Pending My booking

Charts

Dependency-free mini SVG charts (Cerne.Chart.bar/line/donut).

More components

List group, spinner, rating, hero and pricing โ€” for stores, institutional portals, marketing pages and catalogs.

4.2 (128)
<div class="rating">
  <svg class="is-filled"><use href="sprite.svg#icon-star"></use></svg>
  <!-- ... -->
  <span class="rating-count">4.2 (128)</span>
</div>

Images

Cropping (object-fit/aspect-ratio), CSS filters (grayscale, blur-*, brightness-*...) and ready-made treatment recipes (hover zoom, scrim for a caption, duotone, organic clip-path) โ€” all pure CSS, with no image-processing library. The photos on this page are original SVG illustrations, so the docs stay 100% self-contained.

Cropping & aspect ratio

.aspect-video/.aspect-square/.aspect-portrait fix the container's aspect ratio; .object-cover fills it without distortion.

Illustration of mountains at sunset aspect-video
Abstract portrait illustration aspect-square
Illustration of mountains at sunset aspect-portrait
<img class="aspect-video object-cover rounded-md" src="foto.jpg" alt="..." />

Filters

Atomic, composable classes (class="grayscale contrast-125") โ€” each one controls a single filter property.

No filter no filter
Grayscale filter grayscale
Sepia filter sepia
Blur-sm filter blur-sm
Brightness-50 filter brightness-50
Brightness-150 filter brightness-150
Contrast-150 filter contrast-150
Saturate-0 filter saturate-0
Saturate-200 filter saturate-200
Hue-rotate-90 filter hue-rotate-90
Invert filter invert
Combined grayscale and contrast-125 filters grayscale contrast-125
<img class="grayscale" src="foto.jpg" alt="..." />
<img class="sepia" src="foto.jpg" alt="..." />
<img class="blur-sm" src="foto.jpg" alt="..." />
<img class="brightness-150 contrast-125" src="foto.jpg" alt="..." />

Treatments

Recipe classes (several properties each, like .bg-aurora) for common photo-card patterns.

Illustration of mountains at sunset
.img-hover-zoom โ€” hover it
Illustration of mountains at sunset
Valley Trail
.img-scrim โ€” readable caption over the photo
Abstract portrait illustration
.img-duotone
Abstract portrait illustration
.img-blob โ€” organic clip-path
<div class="img-hover-zoom rounded-lg aspect-video">
  <img src="foto.jpg" alt="..." />
</div>

<div class="img-scrim rounded-lg aspect-video">
  <img src="foto.jpg" alt="..." />
  <div class="img-scrim-caption"><strong>Valley Trail</strong></div>
</div>

<div class="img-duotone aspect-square"><img src="foto.jpg" alt="..." /></div>
<div class="img-blob aspect-square"><img src="foto.jpg" alt="..." /></div>

Modern trends

Bento grid, spotlight card, gradient border, glow, grain/noise, aurora, marquee, FAB and reading-progress bar โ€” current visual techniques, ready for any application.

Bento grid Apple-style asymmetric grid, with a spotlight on hover.
Simple item
Gradient border
Card with gradient border

Marquee (pauses on hover)

Design System Accessibility Dark mode RTL Design System Accessibility Dark mode RTL
This block uses data-cerne-reveal โ€” scroll the page to see it animate.
<div class="bento-grid">
  <div class="bento-item bento-span-2 card-spotlight">...</div>
  <div class="bento-item">...</div>
</div>

<div data-cerne-reveal="up">Appears while scrolling the page</div>
<span data-cerne-count-up="1284" data-cerne-count-up-format>0</span>

Utility variants & regional adaptation

hover:, focus:, focus-visible:, active:, disabled:, focus-within: and dark: in front of any color/shadow/opacity utility, plus group-hover:/peer-checked: in pure CSS (no JS โ€” .group/.peer are just markers), container queries (.cq + cq-md:) and the primitives that make the framework adaptable to UI patterns from any region โ€” not just Western.

Hover this card

The button next to it uses group-hover:opacity-100 โ€” it only appears when the parent (.group) is hovered.

data-density="compact" on <html> multiplies the entire spacing scale at once โ€” it gets closer to the high-information-density pattern common in East Asian portals/e-commerce. .break-keep and .write-vertical cover CJK text-breaking and vertical writing; --cerne-line-height-base automatically becomes more generous under :lang(ar|he|hi|bn|ta|te|th). See the 9 example pages (store/news/dashboard ร— CJK/RTL/South Asia) in View examples.

<div class="group card">
  <button class="opacity-25 group-hover:opacity-100 hover:bg-primary">...</button>
</div>

<div class="cq">
  <div class="flex-col cq-md:flex-row">...</div> <!-- reage ao espaรงo do .cq, nรฃo do viewport -->
</div>

<html data-density="compact"> <!-- or "spacious" -->

Icons

87 original icons in a single SVG sprite (dist/icons/sprite.svg), referenced via <use>.

Accessibility

The target is WCAG 2.1 level AA โ€” the international standard, independent of country or language โ€” not a tool or seal specific to one jurisdiction.

  • Every interactive component has a visible :focus-visible state and keyboard navigation (arrows in tabs/menus, Esc to close, Tab trapped in modals, roving tabindex in tabs).
  • prefers-reduced-motion and prefers-color-scheme are respected automatically, with no extra configuration.
  • Text colors over a solid background were chosen for AA โ€” special attention on warning/info, which use dark text instead of white because white doesn't reach sufficient contrast.
  • Forms associate a label (for/id), an error and aria-invalid; the error state never relies on color alone.
  • Active navigation links get aria-current="page"; landmarks (main, nav, aside) and a single <h1> per page structure the document for screen readers.
  • Descriptive alt text on images/graphics is the responsibility of whoever uses the framework โ€” Cerne can't generate that for you. The Brazilian convention #PraCegoVer ("for the blind to see" โ€” describing the image in its own caption/alt) is a good habit, but the practice that matters โ€” writing an alt that describes the image, not repeating the obvious โ€” holds in any language.
  • About VLibras and sign-language translation tools: they are deliberately not bundled in, since they depend on an external script (a third-party CDN) and are specific to one language/country โ€” which would contradict both "zero external dependencies" and "international framework". The correct, universal foundation is well-built semantic HTML + ARIA, which any assistive technology in the world already knows how to interpret; a specific translation widget can be layered on top, project by project, when it makes sense.
  • Real RTL: components use logical properties (inset-inline-start, margin-inline-end, text-align: start...) instead of fixed left/right, so just dir="rtl" on the <html> is enough to mirror the sidebar, dropdown, tabs, forms and navigation โ€” no extra CSS. See it live:
Card with side accent

The border follows the start of the text, not a fixed side.

<html lang="ar" dir="rtl">
  <!-- sidebar, dropdown, tabs, forms... everything mirrors automatically -->

Privacy & consent

A generic cookie/consent banner โ€” the same "essential / analytics / marketing" pattern used by GDPR (EU), LGPD (Brazil) and CCPA (California), without depending on any third-party consent-management platform.

<div class="consent-banner" data-cerne-consent hidden role="region" aria-label="Cookie notice">
  <p class="consent-banner-text">We use essential cookies...</p>
  <div class="consent-banner-actions">
    <button data-cerne-consent-customize
      data-cerne-toggle="modal" data-cerne-target="#consent-preferences">Customize</button>
    <button data-cerne-consent-reject>Reject non-essential</button>
    <button data-cerne-consent-accept>Accept all</button>
  </div>
</div>

<!-- Cerne.Consent.get() / .set({analytics, marketing}) / .reset() -->

The choice lives in localStorage (key cerne-consent), never in a third-party cookie, and is never sent anywhere โ€” what your backend does with Cerne.Consent.get() is your decision. The banner only appears automatically when the page contains a [data-cerne-consent] element; in this documentation it was deliberately omitted so as not to be intrusive โ€” see the complete example in Blog, Store or Institutional portal.

Complete examples

42 pages built entirely with Cerne, covering an admin dashboard, teaching, management, scheduling, content, a news portal, e-commerce, institutional sites, video, a social network, streaming, a conversational assistant and a portfolio โ€” and each one with its own CJK, RTL, South Asia and Russia variant, with a complete interface translation (168 regional pages, ~210 in total), reachable via the "Regional variant" bar at the top of any example.

Regional variants (CJK, RTL, South Asia, Russia)

Every page of every example above has a CJK, RTL, South Asia and Russia variant โ€” 168 regional pages in total โ€” open any one and use the "Regional variant" bar at the top to switch between them. CJK, RTL and South Asia use the primitives described in Variants & regional โ€” data-density, .break-keep/.write-vertical, dir="rtl" and --cerne-line-height-base per language; the Russia variant uses lang="ru" with Russian text over the same LTR structure as the original example (with no additional logical properties, since Russian behaves like Portuguese in that respect). All 168 pages have a complete translation โ€” not just the interface (navigation, buttons, forms, labels, empty states), but also the dynamic content: product names and descriptions, example emails (subject and body), search results, video/series titles and synopses, the assistant's example conversation, and the body of long articles and posts, each domain with its own per-language copy of the example data (e.g. store-data.cjk.browser.js / store-data.ru.browser.js). The cookie banner was translated too; only small footer notes describing the variant itself (and people's proper names) remain in Portuguese, since they are documentation text for whoever is reading the source code, not app content.

Example CJK RTL South Asia Russia
Admin dashboardOpenOpenOpenOpen
Learning environmentOpenOpenOpenOpen
Teacher pageOpenOpenOpenOpen
Management / CRUDOpenOpenOpenOpen
Room schedulingOpenOpenOpenOpen
BlogOpenOpenOpenOpen
Blog โ€” postOpenOpenOpenOpen
News portalOpenOpenOpenOpen
News portal โ€” articleOpenOpenOpenOpen
E-commerce storeOpenOpenOpenOpen
E-commerce store โ€” productOpenOpenOpenOpen
Lab siteOpenOpenOpenOpen
Institutional portalOpenOpenOpenOpen
Research group siteOpenOpenOpenOpen
Authentication โ€” loginOpenOpenOpenOpen
Authentication โ€” sign-upOpenOpenOpenOpen
Authentication โ€” OTP verificationOpenOpenOpenOpen
Error 404OpenOpenOpenOpen
Error 500OpenOpenOpenOpen
Video platformOpenOpenOpenOpen
Video โ€” watchOpenOpenOpenOpen
Video โ€” playlistOpenOpenOpenOpen
Social network (feed)OpenOpenOpenOpen
Social network (profile)OpenOpenOpenOpen
Streaming โ€” loginOpenOpenOpenOpen
Streaming โ€” profilesOpenOpenOpenOpen
Video streamingOpenOpenOpenOpen
Streaming โ€” title pageOpenOpenOpenOpen
Streaming โ€” watchOpenOpenOpenOpen
Streaming โ€” browseOpenOpenOpenOpen
Streaming โ€” liveOpenOpenOpenOpen
Conversational assistant (LLM)OpenOpenOpenOpen
Portfolio (bento grid)OpenOpenOpenOpen
Analytics dashboardOpenOpenOpenOpen
Webmail (Gmail-style)OpenOpenOpenOpen
Webmail (Outlook-style)OpenOpenOpenOpen
Search engine (minimalist)OpenOpenOpenOpen
Search engine (minimalist) โ€” resultsOpenOpenOpenOpen
Search engine (dense portal)OpenOpenOpenOpen
Search engine (dense portal) โ€” resultsOpenOpenOpenOpen
Smart TV interfaceOpenOpenOpenOpen
Smart TV โ€” playerOpenOpenOpenOpen
Adaptive international registration (already adapts by country via JS โ€” no static variants)โ€”โ€”โ€”โ€”