Skip to Content
Livery is in early development. Star us on GitHub!
StylingVanilla CSS

Vanilla CSS

Use Livery with plain CSS, CSS Modules, or any traditional CSS approach.

CSS Custom Properties

Livery injects CSS custom properties (variables) into your document:

:root { --colors-primary: #0d9488; --colors-secondary: #14b8a6; --colors-background: #ffffff; --colors-surface: #f8fafc; --colors-text: #0f172a; --colors-textMuted: #64748b; --typography-fontFamily-sans: Inter, system-ui, sans-serif; --spacing-md: 1rem; --borderRadius-md: 0.375rem; /* ... */ }

Use these variables in your stylesheets:

.button { background-color: var(--colors-primary); color: var(--colors-textInverse); padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--borderRadius-md); font-family: var(--typography-fontFamily-sans); border: none; cursor: pointer; } .button:hover { opacity: 0.9; }

CSS Modules

Works seamlessly with CSS Modules:

Button.module.css
.button { background-color: var(--colors-primary); color: var(--colors-textInverse); padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--borderRadius-md); border: none; cursor: pointer; transition: opacity 0.2s; } .button:hover { opacity: 0.9; } .buttonSecondary { background-color: var(--colors-secondary); } .buttonOutline { background-color: transparent; border: 1px solid var(--colors-border); color: var(--colors-text); }
Button.tsx
import styles from './Button.module.css'; export function Button({ variant = 'primary', children }) { const variantClass = { primary: '', secondary: styles.buttonSecondary, outline: styles.buttonOutline, }[variant]; return ( <button className={`${styles.button} ${variantClass}`}> {children} </button> ); }

Component Library

Buttons

buttons.css
.btn { display: inline-flex; align-items: center; justify-content: center; padding: var(--spacing-sm) var(--spacing-md); font-family: var(--typography-fontFamily-sans); font-size: var(--typography-fontSize-sm); font-weight: var(--typography-fontWeight-medium); border-radius: var(--borderRadius-md); border: none; cursor: pointer; transition: background-color 0.2s, opacity 0.2s; } .btn-primary { background-color: var(--colors-primary); color: var(--colors-textInverse); } .btn-primary:hover { opacity: 0.9; } .btn-secondary { background-color: var(--colors-secondary); color: var(--colors-textInverse); } .btn-outline { background-color: transparent; border: 1px solid var(--colors-border); color: var(--colors-text); } .btn-outline:hover { background-color: var(--colors-surface); } .btn-sm { padding: var(--spacing-xs) var(--spacing-sm); font-size: var(--typography-fontSize-xs); } .btn-lg { padding: var(--spacing-md) var(--spacing-lg); font-size: var(--typography-fontSize-lg); }

Cards

cards.css
.card { background-color: var(--colors-surface); border: 1px solid var(--colors-border); border-radius: var(--borderRadius-lg); padding: var(--spacing-lg); box-shadow: var(--shadows-sm); } .card-header { margin-bottom: var(--spacing-md); padding-bottom: var(--spacing-md); border-bottom: 1px solid var(--colors-border); } .card-title { font-family: var(--typography-fontFamily-sans); font-size: var(--typography-fontSize-lg); font-weight: var(--typography-fontWeight-semibold); color: var(--colors-text); margin: 0; } .card-body { color: var(--colors-textMuted); font-family: var(--typography-fontFamily-sans); line-height: 1.6; }

Forms

forms.css
.form-group { margin-bottom: var(--spacing-md); } .form-label { display: block; margin-bottom: var(--spacing-xs); font-family: var(--typography-fontFamily-sans); font-size: var(--typography-fontSize-sm); font-weight: var(--typography-fontWeight-medium); color: var(--colors-text); } .form-input { display: block; width: 100%; padding: var(--spacing-sm) var(--spacing-md); font-family: var(--typography-fontFamily-sans); font-size: var(--typography-fontSize-base); color: var(--colors-text); background-color: var(--colors-background); border: 1px solid var(--colors-border); border-radius: var(--borderRadius-md); transition: border-color 0.2s, box-shadow 0.2s; } .form-input:focus { outline: none; border-color: var(--colors-primary); box-shadow: 0 0 0 3px rgba(var(--colors-primary-rgb, 13, 148, 136), 0.1); } .form-input::placeholder { color: var(--colors-textMuted); } .form-error { margin-top: var(--spacing-xs); font-size: var(--typography-fontSize-sm); color: var(--colors-error); }

Fallback Values

Provide fallbacks for CSS variables:

.element { /* Fallback if variable isn't defined */ color: var(--colors-text, #000000); background: var(--colors-background, #ffffff); }

Dark Mode Transitions

Add smooth transitions when switching themes:

* { transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; } /* Respect user preferences */ @media (prefers-reduced-motion: reduce) { * { transition: none; } }

Utility Classes

Create utility classes for common patterns:

utilities.css
/* Colors */ .text-primary { color: var(--colors-primary); } .text-secondary { color: var(--colors-secondary); } .text-muted { color: var(--colors-textMuted); } .bg-primary { background-color: var(--colors-primary); } .bg-surface { background-color: var(--colors-surface); } .border-default { border-color: var(--colors-border); } /* Spacing */ .p-sm { padding: var(--spacing-sm); } .p-md { padding: var(--spacing-md); } .p-lg { padding: var(--spacing-lg); } .m-sm { margin: var(--spacing-sm); } .m-md { margin: var(--spacing-md); } .m-lg { margin: var(--spacing-lg); } /* Border Radius */ .rounded-sm { border-radius: var(--borderRadius-sm); } .rounded-md { border-radius: var(--borderRadius-md); } .rounded-lg { border-radius: var(--borderRadius-lg); } .rounded-full { border-radius: var(--borderRadius-full); } /* Typography */ .font-sans { font-family: var(--typography-fontFamily-sans); } .font-mono { font-family: var(--typography-fontFamily-mono); } .text-xs { font-size: var(--typography-fontSize-xs); } .text-sm { font-size: var(--typography-fontSize-sm); } .text-base { font-size: var(--typography-fontSize-base); } .text-lg { font-size: var(--typography-fontSize-lg); } .text-xl { font-size: var(--typography-fontSize-xl); } /* Shadows */ .shadow-sm { box-shadow: var(--shadows-sm); } .shadow-md { box-shadow: var(--shadows-md); } .shadow-lg { box-shadow: var(--shadows-lg); }

CSS @layer

Organize styles with CSS layers:

@layer base, components, utilities; @layer base { body { font-family: var(--typography-fontFamily-sans); color: var(--colors-text); background-color: var(--colors-background); } } @layer components { .card { background: var(--colors-surface); border-radius: var(--borderRadius-lg); padding: var(--spacing-lg); } } @layer utilities { .text-primary { color: var(--colors-primary); } }

Tips

1. Use Consistent Naming

Match your CSS class names to Livery’s variable naming:

/* Good - consistent naming */ .text-primary { color: var(--colors-primary); } .bg-surface { background: var(--colors-surface); } /* Confusing - inconsistent */ .main-color { color: var(--colors-primary); } .card-bg { background: var(--colors-surface); }

2. Create a Base Stylesheet

base.css
:root { font-family: var(--typography-fontFamily-sans); } body { margin: 0; color: var(--colors-text); background-color: var(--colors-background); line-height: 1.5; } a { color: var(--colors-primary); text-decoration: none; } a:hover { text-decoration: underline; }

3. Use calc() for Derived Values

.large-padding { padding: calc(var(--spacing-lg) * 2); } .half-opacity { opacity: calc(var(--opacity-full, 1) / 2); }
Last updated on