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