Xylem CSS

A very lightweight CSS framework. No JavaScript. No complexity. Just clean, composable CSS utilities.

Typography

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

This is a paragraph. Xylem CSS provides sensible typographic defaults so your content looks good out of the box. It uses system-ui fonts for fast rendering and familiar feel.

Here is a link example within body text.

Show code
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<p>Body text with a <a href="#">link</a>.</p>
<p>Inline <code>code</code> example.</p>

Lists

Unordered

  • Item one
  • Item two
    • Nested item
    • Nested item
  • Item three

Ordered

  1. First
  2. Second
  3. Third
Show code
<ul>
  <li>Item one</li>
  <li>Item two
    <ul>
      <li>Nested</li>
    </ul>
  </li>
</ul>

<ol>
  <li>First</li>
  <li>Second</li>
</ol>

<!-- Unstyled -->
<ul class="list-unstyled">
  <li>No bullets</li>
  <li>No indentation</li>
</ul>

Unstyled

Divided

Show code
<ul class="list-unstyled list-divided">
  <li>Item with separator</li>
  <li>Another item</li>
</ul>

<!-- Works on any parent/children -->
<div class="list-divided">
  <div>First</div>
  <div>Second</div>
</div>

Code

Inline code: .container, .row, .stack

function hello() {
  console.log("Hello");
}
Show code
<p>Inline: <code>.container</code></p>

<pre><code>function hello() {
  console.log("Hello");
}
</code></pre>

Tables

Name Role Status
Alice Designer Active
Bob Developer Active
Carol Manager Away
Show code
<table class="w-full">
  <thead>
    <tr>
      <th>Name</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>Designer</td>
    </tr>
  </tbody>
</table>

Striped

Name Role Status
Alice Designer Active
Bob Developer Active
Carol Manager Away
Dave Intern Active
Show code
<table class="table-striped">
  ...
</table>

Hover

Name Role Status
Alice Designer Active
Bob Developer Active
Carol Manager Away
Dave Intern Active
Show code
<table class="table-hover">
  ...
</table>

<!-- Combine both -->
<table class="table-striped table-hover">
  ...
</table>

Horizontal Rule

Content above the rule.


Content below the rule.

Show code
<hr>

Buttons

Bare <button> elements only inherit font and cursor — no decorative styles. Add .button to opt in to the styled appearance.

Filled

Anchor
Show code
<button class="button">Default</button>
<button class="button button-primary">Primary</button>
<button class="button button-success">Success</button>
<button class="button button-danger">Danger</button>
<button class="button button-warning">Warning</button>
<button class="button button-info">Info</button>
<a class="button" href="#">Anchor</a>
<input type="submit" value="submit input">
<input type="button" value="button input">

Outline

Show code
<button class="button button-outline-primary">Primary</button>
<button class="button button-outline-success">Success</button>
<button class="button button-outline-danger">Danger</button>
<button class="button button-outline-warning">Warning</button>
<button class="button button-outline-info">Info</button>

Disabled

Show code
<button class="button" disabled>Disabled</button>
<button class="button button-primary" disabled>Disabled Primary</button>

With icons

Add .button-icon for proper icon alignment. Works with any icon font — examples below use Phosphor and Lucide.

Phosphor Icons

Lucide Icons

Icon-only

Add .button-sq for square icon-only buttons. Always include aria-label.

Show code
<!-- Phosphor Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/web@2.1.2/src/regular/style.css">

<button class="button button-icon button-primary">
  <i class="ph ph-plus"></i> New item
</button>

<!-- Lucide Icons -->
<link rel="stylesheet" href="https://unpkg.com/lucide-static@latest/font/lucide.css">

<button class="button button-icon button-primary">
  <i class="icon-plus"></i> New item
</button>

<!-- Icon on the right -->
<button class="button button-icon button-outline-primary">
  Settings <i class="icon-settings"></i>
</button>

<!-- Icon-only (always add aria-label) -->
<button class="button button-icon button-sq button-primary" aria-label="Add">
  <i class="icon-plus"></i>
</button>

Small

Show code
<button class="button button-sm">Small</button>
<button class="button button-primary button-sm">Small Primary</button>
<button class="button button-outline-danger button-sm">Small Danger</button>

Badges

Default Primary Success Danger Warning Info
Show code
<span class="badge">Default</span>
<span class="badge badge-primary">Primary</span>
<span class="badge badge-success">Success</span>
<span class="badge badge-danger">Danger</span>
<span class="badge badge-warning">Warning</span>
<span class="badge badge-info">Info</span>

Badges in context

Task Status
Deploy v2.1 Done
Fix login bug Urgent
Update docs Pending
Research SSR Planning
Show code
<td><span class="badge badge-success">Done</span></td>
<td><span class="badge badge-danger">Urgent</span></td>
<td><span class="badge badge-warning">Pending</span></td>

Forms

Show code
<form>
  <div class="row">
    <div class="stack-sm flex-1">
      <label>Name</label>
      <input type="text" class="w-full">
    </div>
    <div class="stack-sm flex-1">
      <label>Email</label>
      <input type="email" class="w-full">
    </div>
  </div>
  <div class="row">
    <div class="stack-sm flex-1">
      <label>Password</label>
      <input type="password" class="w-full">
    </div>
    <div class="stack-sm flex-1">
      <label>Search</label>
      <input type="search" class="w-full">
    </div>
  </div>
  <div class="row">
    <div class="stack-sm flex-1">
      <label>Phone</label>
      <input type="tel" class="w-full">
    </div>
    <div class="stack-sm flex-1">
      <label>URL</label>
      <input type="url" class="w-full">
    </div>
  </div>
  <div class="row">
    <div class="stack-sm flex-1">
      <label>Role</label>
      <select class="w-full">
        <option>Designer</option>
        <option>Developer</option>
        <option>Manager</option>
      </select>
    </div>
    <div class="stack-sm flex-1">
      <label>Disabled select</label>
      <select disabled class="w-full">
        <option>Disabled select</option>
      </select>
    </div>
  </div>
  <div class="stack-sm">
    <label>Plan</label>
    <div class="row">
      <label><input type="radio" name="plan"> Free</label>
      <label><input type="radio" name="plan"> Pro</label>
      <label><input type="radio" checked disabled> Disabled radio</label>
    </div>
  </div>
  <div class="stack-sm">
    <label>Message</label>
    <textarea class="w-full"></textarea>
  </div>
  <div class="stack-sm">
    <label>Terms</label>
    <div class="row">
      <label><input type="checkbox"> I agree to the terms</label>
      <label><input type="checkbox" checked disabled> Disabled checkbox</label>
    </div>
  </div>
  <div class="row mt-4">
    <button type="submit" class="button button-primary">Submit</button>
    <button class="button" disabled>Disabled</button>
    <button class="button button-primary" disabled>Disabled Primary</button>
  </div>
</form>

Switch

Show code
<label>
  <span class="switch">
    <input type="checkbox" role="switch">
    <span class="switch-track"></span>
  </span> Notifications
</label>

<!-- Checked -->
<label>
  <span class="switch">
    <input type="checkbox" role="switch" checked>
    <span class="switch-track"></span>
  </span> Dark mode
</label>

<!-- Disabled -->
<label>
  <span class="switch">
    <input type="checkbox" role="switch" disabled>
    <span class="switch-track"></span>
  </span> Disabled
</label>

<!-- Disabled on -->
<label>
  <span class="switch">
    <input type="checkbox" role="switch" checked disabled>
    <span class="switch-track"></span>
  </span> Disabled on
</label>

Date & Time

Show code
<div class="row">
  <div class="stack-sm flex-1">
    <label>Date</label>
    <input type="date" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Date & Time</label>
    <input type="datetime-local" class="w-full">
  </div>
</div>
<div class="row">
  <div class="stack-sm flex-1">
    <label>Time</label>
    <input type="time" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Month</label>
    <input type="month" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Week</label>
    <input type="week" class="w-full">
  </div>
</div>

Native Controls

Show code
<div class="row">
  <div class="stack-sm flex-1">
    <label>Quantity</label>
    <input type="number" placeholder="1" min="0" max="100" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Price</label>
    <input type="number" placeholder="9.99" step="0.01" min="0" class="w-full">
  </div>
</div>
<div class="row">
  <div class="stack-sm flex-1">
    <label>Range</label>
    <input type="range" min="0" max="100" value="50" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Color</label>
    <input type="color" value="#4a9f4a" class="w-full">
  </div>
</div>
<div class="row">
  <div class="stack-sm flex-1">
    <label>File</label>
    <input type="file" class="w-full">
  </div>
  <div class="stack-sm flex-1">
    <label>Native button</label>
    <button type="button" class="w-full">Native Button</button>
  </div>
</div>

Cards

Placeholder

Card with image

A simple card with an image on top and body content below.

Read more

Simple card

A text-only card without an image. Clean and minimal.

Shadow card

Use .card-shadow for an elevated look with no border.

Learn more
Show code
<!-- Card with image -->
<div class="card">
  <img class="card-img" src="image.jpg" alt="...">
  <div class="card-body">
    <h3 class="card-title">Title</h3>
    <p class="card-text">Description text.</p>
    <a class="button button-primary" href="#">Action</a>
  </div>
</div>

<!-- Card with footer -->
<div class="card">
  <div class="card-body">
    <h3 class="card-title">Title</h3>
    <p class="card-text">Description text.</p>
  </div>
  <div class="card-footer">Footer content</div>
</div>

<!-- Shadow card -->
<div class="card card-shadow">
  <div class="card-body">
    <h3 class="card-title">Title</h3>
    <p class="card-text">Elevated card.</p>
  </div>
</div>

Hero

Default

Small Hero

Use .hero for standard size or add .hero-lg for more vertical space.

With bg-subtle

Build Something Great

A .bg-subtle class helps the hero stand out from the rest of the page.

Show code
<section class="hero">
  <h1>Small Hero</h1>
  <p>Use .hero for standard size or add .hero-lg for more vertical space.</p>
  <button class="button button-primary">Get Started</button>
</section>

<!-- Large variant -->
<section class="hero hero-lg">
  <h1>Big Hero</h1>
  <p>More vertical space.</p>
</section>

<!-- With subtle background -->
<section class="hero bg-subtle">
  <h1>Build Something Great</h1>
  <p>A .bg-subtle class helps the hero stand out from the rest of the page.</p>
</section>

Progress

Show code
<!-- Default (primary) -->
<div class="progress">
  <div class="progress-bar" role="progressbar"
       aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"
       style="width: 75%"></div>
</div>

<!-- Color variants -->
<div class="progress progress-success">
  <div class="progress-bar" role="progressbar"
       aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"
       style="width: 100%"></div>
</div>

<div class="progress progress-warning">
  <div class="progress-bar" role="progressbar"
       aria-valuenow="45" aria-valuemin="0" aria-valuemax="100"
       style="width: 45%"></div>
</div>

<div class="progress progress-danger">
  <div class="progress-bar" role="progressbar"
       aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"
       style="width: 20%"></div>
</div>

<div class="progress progress-info">
  <div class="progress-bar" role="progressbar"
       aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
       style="width: 60%"></div>
</div>

Switch

CSS-only toggle switch. Wrap a checkbox inside .switch with a .switch-track sibling.

Show code
<label>
  <span class="switch">
    <input type="checkbox" role="switch">
    <span class="switch-track"></span>
  </span> Label text
</label>

<!-- Checked -->
<span class="switch">
  <input type="checkbox" role="switch" checked>
  <span class="switch-track"></span>
</span>

<!-- Disabled -->
<span class="switch">
  <input type="checkbox" role="switch" disabled>
  <span class="switch-track"></span>
</span>

Avatar

Circular avatar images with size variants and an interactive toggle for dropdowns.

Sizes

Small avatar Default avatar Large avatar

Avatar toggle

Use .avatar-toggle as a button wrapper — adds a caret and focus ring. Pairs with .dropdown.

Show code
<!-- Sizes -->
<img class="avatar-sm avatar" src="https://i.pravatar.cc/64?img=11" alt="User">
<img class="avatar" src="https://i.pravatar.cc/64?img=11" alt="User">
<img class="avatar-lg avatar" src="https://i.pravatar.cc/64?img=11" alt="User">

<!-- Avatar toggle (pairs with .dropdown) -->
<div class="dropdown">
  <button class="avatar-toggle">
    <img class="avatar" src="https://i.pravatar.cc/64?img=11" alt="User">
  </button>
  <ul class="dropdown-menu">
    <li><a href="#">Profile</a></li>
    <li><a href="#">Sign out</a></li>
  </ul>
</div>

Divider

A horizontal rule with optional inline text, commonly used for "or" separators in forms.

or
continue with
Show code
<div class="divider">or</div>
<div class="divider">continue with</div>

Pagination

Page navigation with active state. Wrap in a <nav> with aria-label for accessibility.

Show code
<nav aria-label="Pagination">
  <ul class="pagination">
    <li><a href="#">&laquo;</a></li>
    <li><span class="active">1</span></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">&raquo;</a></li>
  </ul>
</nav>

Layout

Container

Centered wrapper, max-width 960px.

Show code
<div class="container">
  <!-- Centered, max-width 960px -->
</div>

Row (flex, with gap)

One
Two
Three
Show code
<div class="row">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</div>

<!-- Modifiers -->
<div class="row row-center">...</div>
<div class="row row-between">...</div>
<div class="row row-nowrap">...</div>

Row with .row-between

Left
Right
Show code
<div class="row row-between">
  <div>Left</div>
  <div>Right</div>
</div>

Grid (auto-fill)

Responsive grid that auto-fills columns. Override --xy-grid-min to change minimum column width (default 16rem).

A
B
C
D
Show code
<div class="grid">...</div>

<!-- Custom column width -->
<div class="grid" style="--xy-grid-min: 10rem;">...</div>

Stack (vertical, with gap)

First
Second
Third
Show code
<div class="stack">...</div>
<div class="stack-sm">...</div>
<div class="stack-lg">...</div>

Spacing Utilities

.p-1
.p-2
.p-3
.p-4
.p-5
Show code
<!-- Margin -->
<div class="m-0">...</div>  <!-- 0 -->
<div class="m-1">...</div>  <!-- 0.25rem -->
<div class="m-2">...</div>  <!-- 0.5rem -->
<div class="m-3">...</div>  <!-- 1rem -->
<div class="m-4">...</div>  <!-- 1.5rem -->
<div class="m-5">...</div>  <!-- 2rem -->

<!-- Padding -->
<div class="p-0 .. p-5">...</div>

<!-- Directional (mt, mb, ml, mr, pt, pb, pl, pr) -->
<div class="mt-3">...</div>  <!-- margin-top -->
<div class="mb-2">...</div>  <!-- margin-bottom -->
<div class="ml-3">...</div>  <!-- margin-left -->
<div class="mr-3">...</div>  <!-- margin-right -->
<div class="pt-3">...</div>  <!-- padding-top -->
<div class="pb-2">...</div>  <!-- padding-bottom -->
<div class="pl-3">...</div>  <!-- padding-left -->
<div class="pr-3">...</div>  <!-- padding-right -->
<div class="mx-auto">...</div>  <!-- center -->

Display Utilities

.d-nonedisplay: none
.d-blockdisplay: block
.d-flexdisplay: flex
.d-inlinedisplay: inline
.d-inline-blockdisplay: inline-block
Show code
<div class="d-none">Hidden</div>
<div class="d-block">Block</div>
<div class="d-flex">Flex container</div>
<span class="d-inline-block">Inline block</span>

Flex Utilities

Flex grow

.flex-1
.flex-auto
.flex-none

Alignment

.items-start, .items-center, .items-end, .items-stretch
.justify-start, .justify-center, .justify-end, .justify-between

Gap

A
B
C

Above: .gap-1 (0.25rem). Available: .gap-0 through .gap-5.

Show code
<!-- Flex grow -->
<div class="d-flex gap-3">
  <div class="flex-1">Equal share</div>
  <div class="flex-auto">Natural size, grows</div>
  <div class="flex-none">Fixed</div>
</div>

<!-- Alignment -->
<div class="d-flex items-center justify-between">
  <div>Left</div>
  <div>Right</div>
</div>

<!-- Gap -->
<div class="d-flex gap-2">...</div>

Responsive Utilities

All display and spacing utilities support -sm (≥576px), -md (≥768px), and -lg (≥1024px) breakpoint variants.

Display

ClassApplies at
.d-sm-none≥ 576px
.d-md-block≥ 768px
.d-lg-flex≥ 1024px

Spacing

ClassApplies at
.p-sm-{0-5}, .m-sm-{0-5}≥ 576px
.p-md-{0-5}, .m-md-{0-5}≥ 768px
.p-lg-{0-5}, .m-lg-{0-5}≥ 1024px

Example: hide on mobile, show on desktop

Visible ≥ 768px Resize your browser — element appears at ≥ 768px
Show code
<!-- Hidden on mobile, visible from md breakpoint -->
<div class="d-none d-md-block">Desktop only</div>

<!-- Visible on mobile, hidden from md breakpoint -->
<div class="d-md-none">Mobile only</div>

<!-- Responsive spacing -->
<div class="p-2 p-md-3 p-lg-4">
  Padding grows with screen size
</div>

<!-- Responsive margin -->
<div class="m-1 m-sm-2 m-lg-4">
  Margin grows with screen size
</div>

Text Utilities

Size

.text-xs — 0.7rem

.text-sm — 0.85rem

.text-md — 0.9rem

.text-base (default) — 1rem

.text-lg — 1.15rem

Color

.text-muted

.text-primary

.text-success

.text-danger

.text-warning

.text-info

Font Weight

.font-light (300)

.font-semibold (600)

Section Label / Overline

Display Number

4,200+

Large, light-weight number for stats and pricing.

Background

.bg-subtle — subtle background with border-radius

Meta

Ana Moreira · 7 Mar 2026 · Featured

Inline flex row for metadata (dates, authors, badges).

Alignment

.text-left

.text-center

.text-right

Width

Use .w-full for width: 100% and .max-w-full for max-width: 100%.

Show code
<!-- Size -->
<p class="text-xs">Extra small</p>
<p class="text-sm">Small</p>
<p class="text-md">Medium</p>
<p class="text-base">Base (default)</p>
<p class="text-lg">Large</p>

<!-- Color -->
<p class="text-muted">Muted</p>
<p class="text-primary">Primary</p>
<p class="text-success">Success</p>
<p class="text-danger">Danger</p>
<p class="text-warning">Warning</p>
<p class="text-info">Info</p>

<!-- Font weight -->
<p class="font-light">Light (300)</p>
<p class="font-semibold">Semibold (600)</p>

<!-- Section label / overline -->
<p class="section-label">Section heading</p>
<p class="overline">Overline text</p>

<!-- Display number -->
<div class="display-number">4,200+</div>

<!-- Subtle background -->
<div class="bg-subtle p-3">Highlighted section</div>

<!-- Meta row -->
<div class="meta">
  <span>Author</span>
  <span>&middot;</span>
  <span>Date</span>
</div>

<!-- Alignment -->
<p class="text-left">Left</p>
<p class="text-center">Center</p>
<p class="text-right">Right</p>

<!-- Width -->
<input class="w-full">
<img class="max-w-full">

Design Tokens

Override any --xy-* custom property in your own CSS to theme the entire framework.

Colors

primary
success
danger
warning
info
bg-subtle
border
border-light
muted

Spacing

TokenValue
--xy-space-10.25rem (4px)
--xy-space-20.5rem (8px)
--xy-space-31rem (16px)
--xy-space-41.5rem (24px)
--xy-space-52rem (32px)

Typography

TokenValue
--xy-text-xs0.7rem
--xy-text-sm0.85rem
--xy-text-md0.9rem
--xy-text-base1rem
--xy-text-lg1.15rem

Shadows

--xy-shadow-sm
--xy-shadow-md
Show code
/* Override tokens to theme the framework */
:root {
  --xy-color-primary: #6366f1;
  --xy-color-primary-hover: #4f46e5;
  --xy-radius: 8px;
  --xy-container-width: 1200px;
}

/* All components automatically pick up the new values */

Screen Reader Only

Use .sr-only to visually hide content while keeping it accessible to screen readers.

The button has hidden text: "— open navigation"
Show code
<!-- Hidden label for screen readers -->
<button class="button button-primary">
  Menu <span class="sr-only">— open navigation</span>
</button>

<!-- Skip to content link -->
<a href="#main" class="sr-only">Skip to main content</a>

<!-- Icon-only button with accessible label -->
<button class="button">
  &times; <span class="sr-only">Close</span>
</button>