Consume without Panda
Ship a Panda design system as plain CSS, bundled or split per recipe, for apps that don't run Panda.
If the app doesn't run Panda, designSystem and theme extension are out. Ship it a plain stylesheet instead, in one
file or several.
Emit a stylesheet
Bundled CSS file
Everything in one file. One import for the app, and the least to publish.
panda codegen
panda cssgen --outfile dist/styles.csspackages/ds/package.json
{
"name": "@acme/ds",
"exports": {
".": "./dist/index.js",
"./styles.css": "./dist/styles.css"
},
"files": ["dist"],
"scripts": {
"build": "panda codegen && panda cssgen --outfile dist/styles.css && tsup"
}
}Split CSS files
--splitting writes one file per layer and one per recipe, so a team can load only the recipes it renders. Pass
--outdir to say where they land.
panda codegen
panda cssgen --splitting --outdir dist/pandadist/panda/styles.css # layer order, then imports everything below
dist/panda/styles/reset.css
dist/panda/styles/global.css
dist/panda/styles/tokens.css
dist/panda/styles/utilities.css
dist/panda/styles/recipes.css
dist/panda/styles/recipes/button.css # one per recipe
Export the tree rather than a single file:
packages/ds/package.json
{
"exports": {
"./styles.css": "./dist/panda/styles.css",
"./styles/*": "./dist/panda/styles/*"
},
"files": ["dist"],
"scripts": {
"build": "panda codegen && panda cssgen --splitting --outdir dist/panda && tsup"
}
}The app imports everything, or only the recipes it renders:
import '@acme/ds/styles.css'
import '@acme/ds/styles/recipes/button.css'styles.css is where the @layer declarations live, and the individual files don't repeat them. Skip it and the app
has to set the cascade order itself.
Emit every variant
The app never scans your source, so the sheet holds only what your own components rendered. A recipe they never call is left out entirely; a variant they never pass ships as a class name with no rule behind it.
packages/ds/panda.config.ts
export default defineConfig({
staticCss: {
recipes: '*'
}
})Name the recipes instead of '*' if the same package also ships for designSystem consumers. See
Static CSS.
Import it in the app
The app needs the CSS and your components, nothing else:
src/main.tsx
import '@acme/ds/styles.css'
import { Button } from '@acme/ds'
export function App() {
return <Button>Save</Button>
}Two cases need the app to declare the cascade order itself: it has layered CSS of its own, or it cherry-picked files
instead of importing styles.css. Copy the @layer lines from the top of styles.css into a stylesheet the app loads
first. There are three of them, and the nested recipes.* lines matter as soon as you use more than one recipe.
Managing style conflicts
Two independently built stylesheets can emit the same class names (.button, --colors-brand), and an app without
Panda can't deduplicate them. Set prefix in the library before you publish. Changing it later breaks everyone already
importing your CSS.
packages/ds/panda.config.ts
export default defineConfig({
prefix: 'acme' // .button → .acme-button
})hash and cssVarRoot do the same job differently. See Style isolation.
Example
A Next.js app with no Panda installed, just the published CSS and components:
npx degit chakra-ui/panda-examples/examples/standalone-app my-appstandalone-app (opens in a new tab) in panda-examples.
See also
- Build a design system if you also ship
panda libfor Panda apps - Consume with Panda when the app can run Panda
- Storybook because your stories run Panda even though the app doesn't
panda cssgen