Installation
Drop a single CSS file into your project. No build step, no JavaScript, no dependencies. grit.css weighs in under 10KB gzipped and has zero external dependencies — just download grit.css and link it in your <head>.
Usage
Link the stylesheet and start writing semantic HTML. Headings, paragraphs, links, inputs, and buttons all look polished out of the box — no classes needed. When you want more control, layer on utility classes like .btn-primary, .card, or .row gap-md. Everything composes: you can mix and match without conflicts.
Dark Mode
grit.css supports dark mode in two ways. By default, it reads your system preference via prefers-color-scheme: dark — no extra work required. If you want manual control (e.g., a toggle button), add a .dark class to <html>. You can also force light mode with .light to override a dark system preference. All components, colors, shadows, and borders adapt automatically.
Themes
Themes restyle everything inside a container by overriding grit's CSS custom properties. Apply the built-in .theme-midnight to any element and all child components — buttons, badges, cards, alerts — pick up the new colors automatically. Create your own themes by overriding properties like --grit-primary, --grit-bg, and --grit-surface. You can nest themes, scope them to a single card, or apply them to the whole page.
Buttons
Start with the base .btn class, then add a color variant (.btn-primary, .btn-error, etc.) and optional style modifiers. Use .btn-outline for bordered buttons, .btn-ghost for minimal text-only buttons, and .btn-pill for fully rounded edges. Size modifiers .btn-sm and .btn-lg adjust padding and font size. Add .btn-block for full-width. All buttons support disabled natively.
Cards
Cards are flexible content containers with a subtle border, rounded corners, and an optional shadow on hover. Wrap content in .card-body for padding. Use .card-title for headings and .card-actions for a button row at the bottom. Cards can also hold a top image — just place an <img> before the body and it will fill the card width with rounded top corners.
Badges
Small inline status indicators. Apply a color variant (.badge-primary, .badge-success, .badge-error, etc.) for filled badges, or add .badge-outline for a bordered style. Use .badge-lg for a slightly larger size. Badges work great inside headings, table cells, or next to avatars.
Alerts
Contextual feedback messages with a tinted background and colored left border. Use .alert-info for informational, .alert-success for confirmations, .alert-warning for cautions, and .alert-error for failures. Alerts are block-level and take the full width of their container — perfect for form validation messages, system notifications, or status banners.
Tabs
A horizontal tab bar built with .tabs as the container and .tab on each item. Mark the current tab with .tab-active — it gets an underline and bolder color. Tabs are styled buttons by default, so they work with onclick handlers or as part of a router. The active indicator is a 2px bottom border that transitions smoothly.
Toggles
iOS-style toggle switches built on native <input type="checkbox"> elements — just add the .toggle class. No JavaScript required; the switch state is backed by the real checkbox. The knob slides with a smooth transition and the track changes color when checked. Pair with a <label> for an accessible, clickable label.
Dropdown
Dropdown menus powered by the native <details>/<summary> elements — zero JavaScript. Wrap links inside .dropdown-menu and they'll appear on click with a smooth fade. Use <hr> for dividers between menu groups. The menu auto-positions below the trigger and closes when you click outside.
Modal
Modal dialogs built on the native <dialog> element. Open with el.showModal() and close with el.close() — just two lines of JS, no library needed. The modal centers on screen with a blurred backdrop. Structure content with .modal-body, .modal-title, and .modal-actions. Pressing Escape closes it automatically.
Progress
Lightweight progress bars with a track-and-fill pattern. The outer .progress div provides the gray track, and the inner .progress-bar fills to whatever width you set inline. Color variants — .progress-bar-success, .progress-bar-warning, .progress-bar-error — change the fill color. Great for upload indicators, storage meters, or step-completion visuals.
Avatars
Circular image thumbnails in four sizes. The base .avatar class gives you a 2.5rem circle. Add .avatar-sm (2rem), .avatar-lg (3.5rem), or .avatar-xl (5rem) for different scales. Images are object-fit: cover, so they crop gracefully. Stack avatars in a .row gap-sm for a team member bar.
Tooltips
Pure-CSS tooltips — add a data-tooltip="Your text" attribute to any element and a tooltip appears on hover. No JavaScript, no initialization. The tooltip fades in above the element with a subtle arrow. Works on buttons, links, spans, or any inline/block element. Keep tooltip text short (one line) for best results.
Accordion
Expandable content sections built on native <details>/<summary> — zero JavaScript. Wrap multiple <details> elements in an .accordion container. Each item gets a clickable header with a rotating chevron indicator. Use the open attribute to expand an item by default. Content goes inside .accordion-body.
Tables
Clean, readable data tables. The base .table class adds consistent padding and borders. Add .table-striped for alternating row backgrounds, .table-hover for hover highlights, and .table-bordered for cell borders. Wrap in .table-responsive for horizontal scrolling on narrow screens.
Breadcrumb
Navigation trail showing the current page's location in the hierarchy. Use a <nav> with a .breadcrumb <ul>. Items are separated by / dividers automatically via CSS. The last item is styled as muted text (current page), while earlier items are links.
Pagination
Page navigation for multi-page content. Use a .pagination <nav> with links or spans inside. Mark the current page with .active and unavailable pages with .disabled. The active page gets a filled primary-color background.
List Group
A vertical list of items with borders, perfect for settings menus, notifications, or simple navigation. Use a <ul> or <div> with the .list-group class. Items can be plain <li> elements or <a> links (which get hover highlights). Mark the current item with .active.
Chips
Compact pill-shaped labels for tags, filters, or selections. Apply the .chip class to a <span>. Chips are smaller and more rounded than badges — use them when you need inline tag-like elements that feel tappable.
Divider
A horizontal rule with an optional centered text label. Use a <div class="divider"> with text content, or leave it empty for a plain line. The text appears centered between two lines — great for "or" separators in forms or section breaks.
Skeleton
Loading placeholder shapes that shimmer while content loads. Use .skeleton-text for text lines, .skeleton-title for headings, and .skeleton-avatar for circular placeholders. The shimmer animation runs automatically. Combine multiple skeleton elements to approximate your content layout.
Spinner
Animated loading indicators. The base .spinner class creates a spinning circle. Size variants .spinner-sm and .spinner-lg scale it up or down. The spinner uses currentColor so it inherits whatever text color its parent has.
Toast
Brief notification messages that appear in the corner of the screen. Place a .toast-container (fixed to the viewport corner), then add .toast elements inside it. Color variants — .toast-success, .toast-error, .toast-warning, .toast-info — add a colored left border. Add .toast-out to animate dismissal. Requires a small JS snippet to manage show/hide timing.
Prose
Typographic styling for long-form content like blog posts, articles, or documentation. Wrap your content in a .prose container and headings, paragraphs, lists, blockquotes, code blocks, and links all get comfortable reading styles with proper spacing and line heights. No extra classes needed on the inner elements.
Inputs
Text inputs, selects, and textareas are styled globally — no classes needed. Every input gets consistent padding, border radius, and a colored focus ring that matches --grit-primary. Pair each input with a <label> for accessibility and wrap the pair in a .col gap-xs for standard form spacing. Inputs stretch to fill their container width by default.
Input Groups
Visually attach a prefix or suffix to an input. Wrap an <input> and a .input-group-text span inside .input-group — the addon and input merge into a single bordered row. Use this for currency symbols, "@" username prefixes, search icons, or domain suffixes. The addon inherits the surface background so it's visually distinct from the input area.
Fieldset
Group related form controls with a labeled border. The native <fieldset> element gets clean styling with a subtle border and rounded corners. Use a <legend> for the group title. The .fieldset class is optional — grit styles the native elements directly.
Container
The .container class centers content and caps it at a max-width of 1200px with horizontal padding on each side. Use it as the outermost wrapper for your page content. It works at every viewport width — on mobile it's full-width with padding, on desktop it creates comfortable reading margins. Nest grids, rows, and sections inside it.
Grid
CSS Grid utilities for common column layouts. Start with .grid, then add .grid-2, .grid-3, or .grid-4 for fixed-column layouts. Use .grid-auto for a responsive auto-fit grid that wraps items into rows at 250px minimum width. All grid layouts collapse to a single column on mobile. Use .span-2, .span-3, or .span-full on children to span multiple columns.
Stack
A vertical layout helper that adds consistent spacing between child elements using the lobotomized owl selector (* + *). Apply .stack to a container and every direct child after the first gets a top margin. On mobile, the spacing tightens automatically. Great for article layouts, form sections, or any vertical flow where you want uniform spacing without gap utilities.
Flex Utilities
Flexbox helpers for common layout patterns. .row creates a horizontal flex container (items centered vertically); .col creates a vertical stack. Both accept gap utilities. Use .between for space-between, .center for centering both axes, .end for flex-end, and .wrap for wrapping. .grow makes a child fill available space. Combine freely: .row between wrap gap-md is a common pattern.
Spacing
Control the space between and inside elements with gap and padding utilities. Gap classes set the --gap custom property, which is picked up by .row, .col, and .grid containers. Padding classes add uniform padding on all sides. Both use a consistent size scale so your layouts feel cohesive.
Gap (space between children)
Add a gap class to any flex or grid container. Gap only affects the space between children — it doesn't add space on the outer edges. If no gap class is set, .row, .col, and .grid default to 0.75rem.
| Class | Value | Pixels (at 16px base) | Visual |
|---|---|---|---|
.gap-xs | 0.25rem | 4px | |
.gap-sm | 0.5rem | 8px | |
.gap-md | 1rem | 16px | |
.gap-lg | 1.5rem | 24px | |
.gap-xl | 2rem | 32px |
Padding (space inside an element)
Padding utilities add equal padding on all four sides. Use them on cards, sections, containers, or any element that needs internal breathing room.
| Class | Value | Pixels (at 16px base) | Visual |
|---|---|---|---|
.pad-sm | 0.5rem | 8px | |
.pad | 1rem | 16px | |
.pad-lg | 2rem | 32px | |
.pad-xl | 3rem | 48px |
Margin
.m-auto sets margin: auto — handy for centering a fixed-width element horizontally.
Common patterns
Here are the spacing combos you'll reach for most often: