Appearance
Components
remCSS components use four modern CSS techniques for isolation and intelligence:
@scope— prevents styles leaking out of the component boundary (progressive enhancement)@container— components respond to their parent size, not the viewport:has()— relational state (error fields, icon buttons, loading states)light-dark()— single color definition handles both themes automatically
Buttons
html
<!-- Primary (default) -->
<button class="button">Save Changes</button>
<!-- Outline variant -->
<button class="button button-outline">Cancel</button>
<!-- Ghost variant -->
<button class="button button-ghost">Learn more</button>
<!-- Danger -->
<button class="button button-danger">Delete</button>
<!-- Sizes -->
<button class="button button-sm">Small</button>
<button class="button button-lg">Large</button>
<!-- Disabled (both methods work) -->
<button class="button" disabled>Disabled</button>
<button class="button" aria-disabled="true">Disabled</button>
<!-- Loading (aria-busy) -->
<button class="button" aria-busy="true">Loading…</button>
<!-- Full width -->
<button class="button button-block">Full Width</button>Button Group
html
<div class="button-group">
<button class="button button-outline">Left</button>
<button class="button button-outline">Center</button>
<button class="button button-outline">Right</button>
</div>Forms
html
<form class="form">
<!-- Text input -->
<div class="field">
<label class="label" for="name">
Full name <span class="required" aria-hidden="true">*</span>
</label>
<input class="input" type="text" id="name" required placeholder="Jane Smith" />
<span class="field-hint">As it appears on your ID.</span>
<span class="field-error" aria-live="polite">Please enter your full name.</span>
</div>
<!-- Select -->
<div class="field">
<label class="label" for="country">Country</label>
<select id="country">
<option value="">Choose a country…</option>
<option value="de">Germany</option>
<option value="us">United States</option>
</select>
</div>
<!-- Textarea -->
<div class="field">
<label class="label" for="message">Message</label>
<textarea id="message" rows="4"></textarea>
</div>
<!-- Checkbox group -->
<div class="field">
<span class="label">Notifications</span>
<div class="check-group">
<label class="check-label"> <input type="checkbox" checked /> Email </label>
<label class="check-label"> <input type="checkbox" /> SMS </label>
</div>
</div>
<button class="button" type="submit">Submit</button>
</form>Error States
Error styles are applied automatically using :has(:invalid:not(:placeholder-shown)) — no JavaScript required:
html
<div class="field">
<label class="label" for="email">Email</label>
<!-- When this input is invalid and has been interacted with,
the parent .field gets --field-border-color: var(--color-danger) -->
<input type="email" id="email" required value="not-an-email" />
<span class="field-error">Please enter a valid email address.</span>
</div>Tables
Wrap tables in .table-wrapper for horizontal scroll and rounded corners:
html
<div class="table-wrapper">
<table class="table table-striped table-hover">
<caption>
Q1 2026 Sales by Region
</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col" aria-sort="descending">Revenue</th>
<th scope="col" data-numeric>Units</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Europe</td>
<td data-numeric>€1,284,000</td>
<td data-numeric>3,420</td>
<td data-status="success">On track</td>
</tr>
<tr>
<td>North America</td>
<td data-numeric>$980,000</td>
<td data-numeric>2,100</td>
<td data-status="warning">At risk</td>
</tr>
</tbody>
</table>
</div>Responsive Stacking
Add .table-responsive for column-to-card stacking on narrow containers. Use data-label attributes to provide column headers in the stacked view:
html
<div class="table-wrapper">
<table class="table table-responsive">
<thead>
<tr>
<th>Name</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Name">Jane Smith</td>
<td data-label="Amount" data-numeric>€420</td>
</tr>
</tbody>
</table>
</div>Typography
Headings, paragraphs, and text elements are styled automatically — no class required.
html
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<p>
Body paragraph text. Max line length is constrained to <code>--measure</code> (66ch) automatically
for optimal readability. Text wrapping uses <code>text-wrap: pretty</code>
to avoid orphaned words.
</p>
<!-- Lead paragraph — slightly larger -->
<p class="lead">An introductory paragraph with <code>--text-lg</code> size and wider measure.</p>Font weight classes
html
<p class="font-light">Light (300)</p>
<p class="font-medium">Medium (400)</p>
<p class="font-bold">Bold (700)</p>Text alignment
html
<p class="text-start">Start-aligned (RTL-aware)</p>
<p class="text-center">Centered</p>
<p class="text-end">End-aligned (RTL-aware)</p>Blockquotes & Lists
Blockquote
html
<blockquote>
<p>
The Golden Ratio is a reminder that mathematics and beauty are not separate domains — they are
the same domain.
</p>
<footer>— Luca Pacioli, <cite>De Divina Proportione</cite></footer>
</blockquote>Blockquotes receive a left accent border in --color-accent (orange) and italic styling automatically.
Unordered List
html
<ul>
<li>Golden Ratio scale</li>
<li>rem-only units</li>
<li>oklch() colors</li>
</ul>Ordered List
html
<ol>
<li>Install: <code>npm install @dstn/remcss</code></li>
<li>Link the stylesheet</li>
<li>Use the classes</li>
</ol>Definition List
html
<dl>
<dt>φ (phi)</dt>
<dd>The Golden Ratio — approximately 1.618033988749895</dd>
<dt>rem</dt>
<dd>Root-relative em — the unit everything in remCSS is built on</dd>
<dt>oklch()</dt>
<dd>A perceptually uniform color space used for all color values</dd>
</dl>Unstyled List
Add role="list" to remove list markers when using a list purely for semantics:
html
<ul role="list" class="flex gap-1 flex-wrap">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>Code & Pre
Inline Code
html
<p>Use <code>var(--step-1)</code> for spacing at the base GR step.</p>
<p>Press <kbd>Ctrl</kbd> + <kbd>K</kbd> to open search.</p>
<p>The function returns <samp>true</samp> on success.</p><code>, <kbd>, and <samp> all receive the monospace font stack, a subtle background, and padding automatically.
Preformatted / Code Block
html
<pre><code>@layer base, components, utilities;
:root {
--phi: 1.618033988749895;
--step-1: calc(1rem * var(--phi));
}</code></pre><pre> receives a left accent border in the brand color and horizontal scroll on overflow.
Inline Elements
These elements are styled automatically with no class needed:
html
<p>
<strong>Bold/strong text</strong> and <em>italic/emphasis text</em> and
<mark>highlighted text</mark> and <del>deleted text</del> and <ins>inserted text</ins> and
<small>small print</small> and <sup>superscript</sup> and <sub>subscript</sub>.
</p>
<!-- Abbreviation with tooltip -->
<p>The <abbr title="Golden Ratio">GR</abbr> is approximately 1.618.</p>
<!-- Horizontal rule -->
<hr />Links
Links inherit the accent color and have a custom underline offset. :focus-visible shows a keyboard-accessible focus ring without disrupting mouse users:
html
<a href="/guide/getting-started">Get Started</a>
<a href="https://github.com/dstN/remCSS" rel="noopener noreferrer">GitHub ↗</a>Grid System
The grid component provides responsive layout containers. All layout is handled via CSS — no JavaScript, no class arithmetic.
Auto-Responsive Grid
Columns automatically adjust to available space. Minimum column width: 20rem (~200px):
html
<div class="grid-auto">
<article class="card">Card 1</article>
<article class="card">Card 2</article>
<article class="card">Card 3</article>
<article class="card">Card 4</article>
</div>At narrow widths: single column. At medium: two columns. At wide: as many as fit. No breakpoints written.
Sidebar Layout
A classic two-column layout: sidebar + main content. The sidebar has a natural width; the main takes all remaining space.
html
<div class="grid-sidebar">
<aside class="sidebar">
<nav>Navigation</nav>
</aside>
<main class="main-content">
<h1>Page Title</h1>
<p>Content area</p>
</main>
</div>Explicit Column Grid
html
<!-- 2 columns -->
<div class="grid cols-2 gap-2">
<div>Column A</div>
<div>Column B</div>
</div>
<!-- 3 columns -->
<div class="grid cols-3 gap-2">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
<!-- 4 columns -->
<div class="grid cols-4 gap-3">
<div>Alpha</div>
<div>Beta</div>
<div>Gamma</div>
<div>Delta</div>
</div>Stack (Vertical Rhythm)
A vertical stack with consistent spacing between children:
html
<div class="stack stack-md">
<h2>Section Title</h2>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</div>Stack gap sizes: stack-sm (step-1), stack-md (step-2), stack-lg (step-3), stack-xl (step-4).
Cluster (Inline Group)
Horizontal grouping of items that wraps gracefully:
html
<div class="cluster">
<button class="button">Action 1</button>
<button class="button button-outline">Action 2</button>
<button class="button button-ghost">Cancel</button>
</div>