Getting Started
Porchlight is a native CSS framework with zero JavaScript dependencies. It ships tokens, themes, base styles, layout primitives, component contracts, utilities, and progressive enhancements as prebuilt CSS files.
Install
npm install @cawalch/porchlight
# or
pnpm add @cawalch/porchlight
Full bundle
The package main export is the complete prebuilt stylesheet:
@layer porchlight, app;
@import "@cawalch/porchlight";
@layer app {
/* your product styles here */
}
Use this when you want the whole framework available everywhere.
Import only what you need
For smaller surfaces, start with core.css and add selected layers or
components.
@layer porchlight, app;
@import "@cawalch/porchlight/core.css";
@import "@cawalch/porchlight/layout.css";
@import "@cawalch/porchlight/components/button.css";
@import "@cawalch/porchlight/components/field.css";
@import "@cawalch/porchlight/components/card.css";
@import "@cawalch/porchlight/utilities.css";
core.css includes layer order, reset, tokens, themes, and base styles.
Component files consume those tokens, so keep core.css first.
If you want the whole practical framework without experimental enhancement
syntax, use compat.css. It includes core, layout, all components, and
utilities, but leaves out enhancements.css.
@layer porchlight, app;
@import "@cawalch/porchlight/compat.css";
Static assets
Server-rendered apps can copy prebuilt files from
node_modules/@cawalch/porchlight/dist/ without asking a bundler to parse
modern CSS. Use the included copy helper for the common paths:
npx porchlight copy --out public/porchlight --compat
For a smaller static slice, name the components you use:
npx porchlight copy --out public/porchlight --components button,field --layout --utilities
<link rel="stylesheet" href="/porchlight/core.css" />
<link rel="stylesheet" href="/porchlight/components/button.css" />
<link rel="stylesheet" href="/porchlight/components/field.css" />
<link rel="stylesheet" href="/app.css" />
Then declare the layer order in app CSS:
@layer porchlight, app;
The package also ships dist/porchlight.manifest.json, which lists the
available files, component names, and recommended load order for copy scripts.
Vite
Vite handles CSS @import and rebasing, so the full bundle and partial
imports both work well.
@layer porchlight, app;
@import "@cawalch/porchlight/core.css";
@import "@cawalch/porchlight/components/button.css";
@import "@cawalch/porchlight/components/data-table.css";
@import "@cawalch/porchlight/utilities.css";
You can also import CSS from a JS or TS entry:
import "@cawalch/porchlight/core.css";
import "@cawalch/porchlight/components/button.css";
import "./app.css";
Bun and parser fallbacks
Bun 1.3.14 can bundle compat.css and selected component imports. It may
print non-fatal warnings for @property.
@layer porchlight, app;
@import "@cawalch/porchlight/compat.css";
@layer porchlight, app;
@import "@cawalch/porchlight/core.css";
@import "@cawalch/porchlight/components/button.css";
The full default bundle and enhancements.css include
@container scroll-state(...), which Bun 1.3.14 does not parse. If you need
those enhancement rules, copy the prebuilt files into static assets and load
them with <link>:
bun x porchlight copy --out public/porchlight --full
This also works well for Go, Rails, Django, and other server-rendered applications.
The layer model
Porchlight wraps everything in a single top-level cascade layer:
@layer porchlight. Inside it, sub-layers declare a deterministic order:
@layer porchlight {
@layer reset, tokens, themes, base, layout,
components, utilities, enhancements, print;
}
Later layers win over earlier ones, so a component beats base, a utility
beats a component, and product CSS in @layer app beats Porchlight.
Do not pass layer(...) to Porchlight imports. Modules already
self-layer.
Using components
Each component is a class prefix: .c-*. Drop them into your HTML:
<button class="c-button" data-variant="primary">Save</button>
<div class="c-card">
<div class="c-card__header">
<h2 class="c-card__title">Title</h2>
</div>
<div class="c-card__body">Content</div>
</div>
Browse the component reference or the preview gallery to see every component with live examples.
Token metadata
Use the generated token module for editor autocomplete, validation, or build tooling:
import tokenDoc, { tokenGroups } from "@cawalch/porchlight/tokens";
console.log(tokenDoc.tokens["--pl-color-accent"].value);
console.log(tokenGroups.map((group) => group.name));
JSON is also available:
import tokens from "@cawalch/porchlight/tokens.json";
Exports reference
| Import path | What you get |
|---|---|
@cawalch/porchlight | Full prebuilt CSS bundle |
@cawalch/porchlight/min.css | Minified full bundle |
@cawalch/porchlight/compat.css | Bun-friendly bundle without enhancements |
@cawalch/porchlight/core.css | Layer order, reset, tokens, themes, base |
@cawalch/porchlight/layout.css | Layout primitives |
@cawalch/porchlight/components.css | All component CSS |
@cawalch/porchlight/components/button.css | One component CSS file |
@cawalch/porchlight/utilities.css | Utility classes |
@cawalch/porchlight/enhancements.css | Progressive enhancement layer |
@cawalch/porchlight/tokens | Typed token metadata module |
@cawalch/porchlight/tokens.json | Token metadata JSON |
@cawalch/porchlight/manifest.json | Static-copy manifest |
@cawalch/porchlight/src/* | Raw source escape hatch |
Browser support
Porchlight targets modern browsers and does not polyfill old CSS engines.
The core uses cascade layers, custom properties, :has(), @scope,
color-mix(), and OKLCH. Advanced features are gated where possible.
See the Browser Support guide for the full feature matrix.
Next steps
- Theming guide - override tokens and create a brand theme
- Architecture guide - deep dive into the layer model
- Composition Recipes - compose dashboards, tables, settings, and dense admin screens
- Preview gallery - see every component live