ply

A ratio-based CSS framework built for AI agents, accessible by default, and small enough to ship anywhere. One stylesheet. ~18KB gzipped. No JavaScript, no build step, no configuration.


Why ply exists

CSS frameworks were designed for humans reading documentation. But increasingly, the first consumer of your framework is an AI — a coding agent in Replit, Claude, Cursor, or Copilot generating a UI from a prompt. ply is designed for that world.

AI-Native

Ships with PLY.md and ply-classes.json — a complete class reference any AI agent can read. Class names are predictable: .alert-blue, .btn-sm, .unit-50. An LLM guesses correctly on the first try.

Accessible by Default

Accessibility is a civil rights issue. When your UI isn't accessible, you exclude people. ply bakes :focus-visible outlines, prefers-reduced-motion, semantic HTML styling, and WCAG AA contrast into the CSS itself.

Small Footprint

~18KB gzipped, full framework. No JavaScript runtime. No build step. No tree-shaking. One <link> tag. That matters when you're spinning up prototypes in Replit or shipping to users on slow connections.


Every HTML element, styled

ply styles semantic HTML so you get good defaults without adding classes. Below is every native element ply enhances.

Headings

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

Inline Text

This is a paragraph with bold text, italic text, a link, inline code, Ctrl+S, highlighted text, small text, abbr, and deleted text.

Superscript: x2 and subscript: H2O.

123 Example St, Internet, WWW 00000

Blockquote

Design is not just what it looks like and feels like. Design is how it works.

Ordered List

  1. First item
  2. Second item
    1. Nested item
  3. Third item

Unordered List

  • First item
  • Second item
    • Nested item
  • Third item

Definition List

ply
A ratio-based CSS framework built for AI agents.
Accessible
Designed to be usable by everyone, including people who rely on assistive technology.
Ratio-based
Grid columns defined as percentages of the parent: unit-50, unit-33, unit-25.

Details & Summary

Click to expand — native HTML disclosure

This is a <details> element. It works with keyboard navigation, screen readers, and requires zero JavaScript. ply styles the indicator and spacing.

Another disclosure widget

Multiple details elements stack naturally.

Preformatted Code

<div class="units-row">
  <div class="unit-50 tablet-unit-100">
    <h2>Left column</h2>
    <p>Content here.</p>
  </div>
  <div class="unit-50 tablet-unit-100">
    <h2>Right column</h2>
    <p>More content.</p>
  </div>
</div>

Table

Feature ply Tailwind Bootstrap
Size (gzip) ~18KB ~10KB+ (varies) ~30KB
Build step No Yes No
AI instruction file PLY.md + JSON No No
Dark mode Automatic Automatic (v4) Attribute-based
Custom themes CSS custom properties Config / CSS Sass + CSS vars
Focus styles Built-in Utility-based Built-in
Reduced motion Built-in Utility-based Built-in

Form Elements

Checkboxes & Radios

Choose your options
Pick one

Input States

Input Groups

https://

Progress & Meter

Dialog (Modal)

Native <dialog> element — no JavaScript library required.

Native Dialog

This is a <dialog> element styled by ply. It supports backdrop, focus trapping (browser-native), and Escape to close.

Horizontal Rule

Content above the rule.


Content below the rule.


ply components

Buttons

Button Group

Alerts

Info — This is a blue alert for informational messages.
Success — Operation completed successfully.
Warning — Please review before continuing.
Error — Something went wrong.
Neutral — A general-purpose notification.

Alert Variants

Outlined blue alert.
Ghost blue alert — transparent background.

Navigation Pills

Tabs

Breadcrumbs

Pagination

Labels

Default Blue Red Green Yellow Black

Layers & Depth

ply provides a 4-level elevation system using CSS custom properties. Each layer has a background and corresponding shadow that adapts across all themes.

Layer 0

Base surface. No elevation.

Layer 1

Cards, panels. Subtle lift.

Layer 2

Dropdowns, popovers.

Layer 3

Modals, dialogs.

Shadow Utilities

Apply shadows independently with .shadow-1, .shadow-2, .shadow-3:

.shadow-1 — subtle
.shadow-2 — medium
.shadow-3 — pronounced

CSS Custom Properties

/* Use in your own CSS */
.my-card {
  background: var(--ply-layer-1);
  box-shadow: var(--ply-shadow-2);
}

/* Or use the utility classes */
<div class="layer-2">Elevated content</div>
<div class="shadow-1">Subtle shadow only</div>

Build Your Own Theme

ply uses CSS custom properties (--ply-*) for every color, border, shadow, and layer. To create a custom theme, override these tokens in a [data-theme] selector and set that attribute on <html>. No Sass, no build step.

Three steps

<!-- 1. Define your theme in a <style> block or stylesheet -->
<style>
  [data-theme="brand"] {
    --ply-bg-body: #fefce8;
    --ply-bg-surface: #ffffff;
    --ply-color-body: #1a1a1a;
    --ply-color-link: #b45309;
    --ply-border-color: #d6d3d1;
    --ply-btn-default-bg: #b45309;
    --ply-btn-default-hover: #92400e;
    /* override as many or as few tokens as you need */
  }
</style>

<!-- 2. Activate it -->
<html data-theme="brand">

<!-- 3. Or switch at runtime -->
<script>
  document.documentElement.setAttribute('data-theme', 'brand');
</script>

Built-in modes

ply ships with light and dark. Dark mode activates automatically via prefers-color-scheme, or you can force it with data-theme="dark".

Everything adapts

All components — alerts, buttons, forms, navigation, tables, layers — read from --ply-* tokens. Override the tokens and every component follows.

Token reference

TokenPurpose
--ply-bg-bodyPage background
--ply-bg-surfaceCard / panel background
--ply-bg-surface-altAlternating surface
--ply-bg-mutedMuted / disabled background
--ply-color-bodyPrimary text
--ply-color-headingsHeading text
--ply-color-secondarySecondary text
--ply-color-mutedMuted text
--ply-color-text-inverseText on dark buttons
--ply-border-colorDefault borders
--ply-color-linkLink color
--ply-color-focusFocus ring
--ply-color-input-bgInput background
--ply-color-input-borderInput border
--ply-btn-default-bgDefault button
--ply-nav-bgNavigation background
--ply-layer-03Elevation backgrounds
--ply-shadow-13Elevation shadows

See custom-theme.html for a full working example with two custom themes (Midnight and Warm).


Type Scale

text-5xl

text-4xl

text-3xl

text-2xl

text-xl

text-lg

text-base

text-sm

text-xs


Get Started

Add one line to your HTML:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ply-css@1/dist/css/ply.min.css">

That's it. Write semantic HTML. ply handles the rest.