Purissimo Catalog

Every component, variant, state, and utility — all in one place.

Typography

Heading classes, text sizes, and font weights.

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6
<h1 class="heading-1">Heading 1</h1>
<h2 class="heading-2">Heading 2</h2>
<h3 class="heading-3">Heading 3</h3>
<h4 class="heading-4">Heading 4</h4>
<h5 class="heading-5">Heading 5</h5>
<h6 class="heading-6">Heading 6</h6>

Text large — .text-lg

Text base (default)

Text small — .text-sm

Text extra small — .text-xs

<p class="text-lg">Text large</p>
<p>Text base (default)</p>
<p class="text-sm">Text small</p>
<p class="text-xs">Text extra small</p>

This text uses .text-muted for secondary content.

<p class="text-muted">Muted text</p>

Font light (300) — .font-light

Font regular (400) — .font-regular

Font medium (500) — .font-medium

Font semibold (600) — .font-semibold

Font bold (700) — .font-bold

<p class="font-light">Light</p>
<p class="font-regular">Regular</p>
<p class="font-medium">Medium</p>
<p class="font-semibold">Semibold</p>
<p class="font-bold">Bold</p>

Icons

Material Symbols Outlined icons via the .icon class. Only subseted icons are loaded for performance.

info check_circle warning error close
<span class="icon" aria-hidden="true">info</span>
<span class="icon" aria-hidden="true">check_circle</span>
<span class="icon" aria-hidden="true">warning</span>
<span class="icon" aria-hidden="true">error</span>
<span class="icon" aria-hidden="true">close</span>
<div class="alert alert--info" role="alert">
  <span class="alert__icon icon" aria-hidden="true">info</span>
  <p class="alert__message">Informational message.</p>
</div>
<a href="#close" class="modal__close" aria-label="Close">
  <span class="icon" aria-hidden="true">close</span>
</a>

Buttons

Button variants, sizes, states, and link-as-button patterns.

<button class="btn btn--primary">Primary</button>
<button class="btn btn--secondary">Secondary</button>
<button class="btn btn--ghost">Ghost</button>
<button class="btn btn--primary btn--sm">Small</button>
<button class="btn btn--primary">Default</button>
<button class="btn btn--primary btn--lg">Large</button>
<button class="btn btn--primary" disabled>Primary Disabled</button>
<button class="btn btn--secondary" disabled>Secondary Disabled</button>
<button class="btn btn--ghost" disabled>Ghost Disabled</button>
Primary Link Secondary Link Ghost Link
<a href="#" class="btn btn--primary">Primary Link</a>
<a href="#" class="btn btn--secondary">Secondary Link</a>
<a href="#" class="btn btn--ghost">Ghost Link</a>
  • Use <button> for actions, <a class="btn"> for navigation
  • Choose variant by importance: primary for main action, secondary for alternatives
  • Add disabled attribute when action is unavailable
  • Don't use <div> or <span> as buttons
  • Don't nest buttons inside other buttons or links
  • Don't use multiple primary buttons in the same context

Links

Link styles for body text, subtle contexts, and navigation.

Default link style
<a href="#" class="link">Default link style</a>
Subtle link style
<a href="#" class="link--subtle">Subtle link style</a>
Nav Link Active Nav Link
<a href="#" class="link--nav">Nav Link</a>
<a href="#" class="link--nav" aria-current="page">Active Nav Link</a>

Forms

Inputs, textareas, selects, checkboxes, radios, toggles, hints, and fieldsets.

<div class="form-field">
  <label class="form-label" for="name">Name</label>
  <input type="text" id="name" class="form-input" placeholder="Enter text">
</div>

Focus, valid, and invalid states activate on user interaction via :user-valid and :user-invalid.

<textarea class="form-textarea" rows="3" placeholder="Enter message..."></textarea>
<select class="form-select">
  <option value="">Choose option...</option>
  <option value="1">Option 1</option>
</select>

Must be 3-20 characters with no spaces.

<p class="form-hint">Must be 3-20 characters with no spaces.</p>
<label class="form-checkbox">
  <input type="checkbox">
  <span class="form-checkbox__indicator"></span>
  <span class="form-checkbox__label">Label</span>
</label>
Choose one
<label class="form-radio">
  <input type="radio" name="group" value="a">
  <span class="form-radio__indicator"></span>
  <span class="form-radio__label">Option</span>
</label>
<label class="form-toggle">
  <input type="checkbox">
  <span class="form-toggle__track"></span>
  <span class="form-toggle__label">Label</span>
</label>
Personal Information
<fieldset class="form-fieldset">
  <legend class="form-legend">Personal Information</legend>
  <!-- fields -->
</fieldset>
  • Always pair <label> with matching for/id
  • Include indicator spans for custom checkbox/radio/toggle
  • Use semantic input types (email, tel, url)
  • Don't skip labels — use .sr-only if visually hidden
  • Don't omit .form-checkbox__indicator or .form-radio__indicator
  • Don't use placeholder as a replacement for labels

Tables

Base table with striped and bordered variants.

NameRoleStatus
AliceDesignerActive
BobDeveloperActive
CarolManagerAway
<table class="table">...</table>
NameRoleStatus
AliceDesignerActive
BobDeveloperActive
CarolManagerAway
DaveQAActive
<table class="table table--striped">...</table>
NameRoleStatus
AliceDesignerActive
BobDeveloperActive
CarolManagerAway
<table class="table table--bordered">...</table>
NameRoleStatus
AliceDesignerActive
BobDeveloperActive
CarolManagerAway
DaveQAActive
<table class="table table--striped table--bordered">...</table>
  • Use <thead> and <tbody> for semantic structure
  • Use table--striped for tables with many rows
  • Keep column count reasonable for mobile readability
  • Don't use tables for layout — use Grid or Flexbox
  • Don't skip <th> elements in the header row
  • Don't put complex interactive components inside cells

Cards

Card container with header, body, footer, and style variants.

Default Card

This is the default card style with a subtle background.

Elevated Card

Elevated card with a shadow for visual depth.

Outlined Card

Outlined card with a visible border for separation.

Glass Card

Glassmorphism effect with backdrop blur. Best on darker or image backgrounds.

<article class="card card--elevated">
  <header class="card__header">
    <h3 class="card__title">Title</h3>
  </header>
  <div class="card__body"><p>Content</p></div>
  <footer class="card__footer">
    <a href="#" class="btn btn--primary btn--sm">Action</a>
  </footer>
</article>
  • Use <article> as the card container
  • Maintain header/body/footer structure for consistency
  • Use card--elevated or card--outlined for visual hierarchy
  • Don't nest cards inside cards
  • Don't put long-form content in cards — use page sections
  • Don't mix variants in the same grid unless intentional

Alerts

Contextual feedback messages for user actions.

<div class="alert alert--info" role="alert">
  <span class="alert__icon icon" aria-hidden="true">info</span>
  <p class="alert__message">Informational message.</p>
</div>
  • Use the semantic variant matching the message type
  • Always include role="alert" for screen readers
  • Keep messages concise — one or two sentences
  • Don't use alerts for decorative purposes
  • Don't stack more than 3 alerts in sequence
  • Don't omit the icon — it provides a non-color cue

Navigation

Navbar and breadcrumb components.

<nav class="navbar" aria-label="Main navigation">
  <a href="/" class="navbar__brand">Brand</a>
  <ul class="navbar__menu">
    <li><a href="#" class="navbar__link" aria-current="page">Home</a></li>
    <li><a href="#" class="navbar__link">About</a></li>
  </ul>
</nav>
<nav class="breadcrumb" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Home</a></li>
    <li><a href="#">Components</a></li>
    <li aria-current="page">Current</li>
  </ol>
</nav>
  • Always add aria-label to <nav> elements
  • Mark the current page with aria-current="page"
  • Use <ol> in breadcrumbs — order matters semantically
  • Don't use <div> for navigation — use <nav>
  • Don't make the last breadcrumb item a link
  • Don't have multiple navbars without distinct labels

Accordion

Expandable content sections using native details/summary.

First item (open by default)

This accordion item starts open. Content is revealed when the header is clicked.

Second item

Click to expand this section. Each item is independent.

Third item

Multiple items can be open at once since each is a native details element.

<div class="accordion">
  <details class="accordion__item" open>
    <summary class="accordion__header">Title</summary>
    <div class="accordion__content"><p>Content</p></div>
  </details>
</div>
  • Use native <details>/<summary> — keyboard support built-in
  • Keep headers concise and descriptive
  • Group related items in a single .accordion container
  • Don't nest accordions inside accordions
  • Don't use accordions to hide critical information
  • Don't replace navigation or tabs with accordions

Tabs

Tab navigation using CSS-only radio input technique.

Overview panel content. This is the first tab.

Features panel content. This is the second tab.

Setup panel content. This is the third tab.

Panel 1 content.

Panel 2 content.

Panel 3 content.

Panel 4 content.

Panel 5 content.

<div class="tabs">
  <input type="radio" name="tab-group" id="tab-1" class="tabs__input" checked>
  <label for="tab-1" class="tabs__label">Tab 1</label>
  <!-- repeat for each tab -->
  <div class="tabs__panels">
    <div class="tabs__panel"><p>Content</p></div>
    <!-- one panel per tab -->
  </div>
</div>
  • Match the number of panels to the number of radio inputs
  • Set one tab as checked by default
  • Use unique name attributes per tab group
  • Don't exceed 5 tabs — use different navigation for more
  • Don't use tabs for sequential steps — use a stepper
  • Don't reuse the same name across tab groups

Modal

CSS-only modal using :target selector. Click the button to open.

Open Modal
<a href="#my-modal" class="btn btn--primary">Open Modal</a>

<div id="my-modal" class="modal">
  <a href="#close" class="modal__overlay" tabindex="-1" aria-hidden="true"></a>
  <div class="modal__content" role="dialog" aria-modal="true" aria-labelledby="modal-title">
    <header class="modal__header">
      <h4 id="modal-title" class="modal__title">Title</h4>
      <a href="#close" class="modal__close" aria-label="Close modal"><span class="icon" aria-hidden="true">close</span></a>
    </header>
    <div class="modal__body"><p>Content</p></div>
    <footer class="modal__footer">
      <a href="#close" class="btn btn--secondary">Cancel</a>
      <a href="#close" class="btn btn--primary">Confirm</a>
    </footer>
  </div>
</div>
  • Include role="dialog" and aria-modal="true"
  • Link the title with aria-labelledby
  • Provide both close button and overlay dismiss
  • Don't open a modal from within another modal
  • Don't use modals for simple confirmations
  • Don't omit the close button or overlay

Tooltip

Hover and focus-triggered tooltips via CSS.

Hover over me This is a tooltip
<span class="tooltip">
  Hover over me
  <span class="tooltip__content">Tooltip text</span>
</span>
<button class="tooltip btn btn--secondary" aria-describedby="tip-id">
  Focus me
  <span class="tooltip__content" role="tooltip" id="tip-id">Tooltip text</span>
</button>
  • Use aria-describedby to link trigger to tooltip
  • Add role="tooltip" on the content element
  • Keep tooltip text short — one sentence or a few words
  • Don't put interactive content inside tooltips
  • Don't use tooltips for essential information
  • Don't rely only on hover — ensure focus also triggers

Badges

Small status labels and counters.

Default Primary Success Warning Error
<span class="badge">Default</span>
<span class="badge badge--primary">Primary</span>
<span class="badge badge--success">Success</span>
<span class="badge badge--warning">Warning</span>
<span class="badge badge--error">Error</span>

Dividers

Horizontal rules for content separation.

Content above


Content below

Content above


Content below

<hr class="divider">
<hr class="divider divider--subtle">

Blockquote & Code

Quotations, inline code, code blocks, and keyboard keys.

The purest water on Earth flows beneath Antarctic ice — untouched, essential, enough.

Purissimo Manifesto
<blockquote class="blockquote">
  <p>Quote text</p>
  <footer class="blockquote__footer">
    <cite>Attribution</cite>
  </footer>
</blockquote>

Use the .container class for centered content with a max-width.

<code class="code">.container</code>
<link rel="stylesheet" href="purissimo.css">

Press Ctrl + S to save, or Esc to close.

<kbd>Ctrl</kbd> + <kbd>S</kbd>

Lists

Unordered, ordered, and unstyled list variants.

  • First item
  • Second item
  • Third item
<ul class="list">
  <li>Item</li>
</ul>
  1. First step
  2. Second step
  3. Third step
<ol class="list list--ordered">
  <li>Step</li>
</ol>
  • No bullet item
  • No bullet item
  • No bullet item
<ul class="list list--none">
  <li>Item</li>
</ul>

Figures

Images with captions using the figure component.

Purissimo design system preview
Purissimo — a minimalist design system.
<figure class="figure">
  <img class="figure__image" src="image.jpg" alt="Description">
  <figcaption class="figure__caption">Caption text</figcaption>
</figure>

Grid & Containers

Container widths, 12-column grid, responsive columns, and gap utilities.

.container (max 1200px)
.container--narrow (max 800px)
.container--wide (max 1400px)
1
1
1
1
1
1
1
1
1
1
1
1
col-12
col-6
col-6
col-4
col-4
col-4
col-3
col-3
col-3
col-3
col-8
col-4
col-3
col-6
col-3
<div class="grid gap-2">
  <div class="col-8">...</div>
  <div class="col-4">...</div>
</div>
12 / sm:6 / md:4 / lg:3
12 / sm:6 / md:4 / lg:3
12 / sm:6 / md:4 / lg:3
12 / sm:6 / md:4 / lg:3

Resize the browser to see columns reflow at sm (640px), md (768px), lg (1024px) breakpoints.

<div class="col-12 sm:col-6 md:col-4 lg:col-3">...</div>

gap-1

A
B
C
D

gap-4

A
B
C
D

gap-8

A
B
C
D
<div class="grid gap-1">...</div>
<div class="grid gap-4">...</div>
<div class="grid gap-8">...</div>

Spacing

Margin and padding utility classes (base-4 scale).

Colored area = margin, white area = element

.m-1 (4px)

m-1

.m-2 (8px)

m-2

.m-4 (16px)

m-4

.m-6 (24px)

m-6

.m-8 (32px)

m-8

Directional: .mt-4, .mb-4, .mx-4, .my-4

<!-- Full margin -->
<div class="m-4">...</div>

<!-- Directional -->
<div class="mt-4">...</div>  <!-- top -->
<div class="mb-4">...</div>  <!-- bottom -->
<div class="mx-4">...</div>  <!-- horizontal -->
<div class="my-4">...</div>  <!-- vertical -->
<div class="mx-auto">...</div>  <!-- center horizontally -->

Colored area = padding, inner area = content

.p-1 (4px)

p-1

.p-2 (8px)

p-2

.p-4 (16px)

p-4

.p-6 (24px)

p-6

.p-8 (32px)

p-8

Directional: .pt-4, .pb-4, .px-4, .py-4

<!-- Full padding -->
<div class="p-4">...</div>

<!-- Directional -->
<div class="pt-4">...</div>  <!-- top -->
<div class="pb-4">...</div>  <!-- bottom -->
<div class="px-4">...</div>  <!-- horizontal -->
<div class="py-4">...</div>  <!-- vertical -->

Display & Flex

Display modes, flex direction, justify, and align utilities.

.block (full width)
.inline .inline
.inline-block .inline-block
.flex child .flex child
.hidden element is here but invisible
<div class="block">...</div>
<span class="inline">...</span>
<span class="inline-block">...</span>
<div class="flex">...</div>
<div class="grid">...</div>
<div class="hidden">...</div>

.flex-row (default)

A B C

.flex-col

A B C
<div class="flex flex-row gap-2">...</div>
<div class="flex flex-col gap-2">...</div>

.justify-start

ABC

.justify-center

ABC

.justify-end

ABC

.justify-between

ABC

.items-start

ShortTallShort

.items-center

ShortTallShort

.items-end

ShortTallShort

.items-stretch

ABC
<div class="flex items-center justify-between">...</div>

Text & Font Utilities

Text alignment and screen reader utility.

.text-left

.text-center

.text-right

<p class="text-left">...</p>
<p class="text-center">...</p>
<p class="text-right">...</p>

The .sr-only class visually hides content while keeping it accessible to screen readers. The text below is present in the DOM but invisible:

This text is only visible to screen readers.

Inspect the DOM to see the hidden <span class="sr-only"> element above.

<span class="sr-only">Accessible label</span>

Width & Overflow

Width constraints and overflow behavior.

.w-full (100% width)

.w-full

.w-auto (intrinsic width)

.w-auto

.overflow-auto (scrollable when content overflows)

Line 1 of scrollable content

Line 2 of scrollable content

Line 3 of scrollable content

Line 4 of scrollable content

Line 5 of scrollable content

Line 6 of scrollable content

<div class="w-full">...</div>
<div class="w-auto">...</div>
<div class="overflow-auto">...</div>

Accessibility

Built-in accessibility features and user preference support.

The .skip-link is positioned off-screen and becomes visible when focused via keyboard (Tab). Try pressing Tab on this page to see it.

<a href="#main" class="skip-link">Skip to main content</a>

When the user has prefers-reduced-motion: reduce enabled in their OS settings, all transitions and animations are effectively disabled (set to 0.01ms). This respects users who experience motion sickness or prefer less visual movement.

No demo needed — this is automatic based on OS/browser settings.

/* Applied automatically via CSS */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

When prefers-contrast: more is active, Purissimo enhances borders, removes subtle shadows, and increases contrast on interactive elements like buttons, badges, tooltips, and form toggles.

No demo needed — this is automatic based on OS/browser settings.

/* Applied automatically via CSS */
@media (prefers-contrast: more) {
  :root {
    --color-border: var(--gray-500);
    --shadow-sm: none;
    /* ... enhanced styles */
  }
}

All interactive elements have visible :focus-visible outlines. Tab through these elements to see the focus ring:

Link