Skip to content

The css() function

Edit this page

css() takes one hash of styles and returns a string of class names. Use it wherever a class name goes:

1
2
3
4
<div class="{{ css({ display: 'flex', gap: 'md', p: 'lg' }) }}">

{# with other classes #}
<div class="card {{ css({ p: 'lg' }) }}">

The syntax follows the css() function of Panda CSS, and so do the class names and the CSS.

Properties

Properties are CSS properties written in camelCase: backgroundColor, borderTopWidth, gridTemplateColumns. Panda CSS shorthands are accepted too, and give the same classes as the full name:

Shorthand Property
p, px, py padding, paddingInline, paddingBlock
pt, pr, pb, pl paddingTop, paddingRight, paddingBottom, paddingLeft
m, mx, my margin, marginInline, marginBlock
mt, mr, mb, ml marginTop, marginRight, marginBottom, marginLeft
w, h width, height
minW, maxW minWidth, maxWidth
minH, maxH minHeight, maxHeight
bg, bgColor background, backgroundColor
rounded borderRadius
shadow boxShadow

A CSS variable can be set as a property too: '--card-gap': '[1rem]'.

Values

What a property accepts depends on the property:

  • a property bound to a token category takes a token name, like color: 'primary' or p: 'md'. See Design tokens;
  • a property whose values are keywords takes one of them: display: 'flex', position: 'sticky', textAlign: 'center';
  • a property whose values are numbers takes a number: zIndex: 10, opacity: 0.5, flexGrow: 1;
  • a property with a more complex syntax takes any string: gridTemplateColumns: 'repeat(3, 1fr)'.

Every property also accepts the CSS-wide keywords inherit, initial, unset, revert and revert-layer. It also accepts a value between square brackets (w: '[37ch]') and a CSS variable (gap: 'var(--card-gap)').

A value that ends with ! or !important is written with !important: color: 'primary!'.

A value can contain CSS strings, as long as every quote opens and closes a string. This is how you write a pseudo-element or grid areas:

1
2
3
<blockquote class="{{ css({ _before: { content: '""' } }) }}">

{{ css({ gridTemplateAreas: '"header header" "nav main"' }) }}

A value cannot contain ;, {, }, a backslash, <, a CSS comment, a line break inside a string or a quote that is not part of a complete string, and this applies inside strings too. Write the character itself instead of an escape sequence: content: '"→"', not content: '"\2192"'. A selector or at-rule key cannot contain quotes at all. This stops a style from writing extra CSS rules or breaking the class attribute.

Conditions and breakpoints

A key that starts with an underscore is a condition. A breakpoint name is a breakpoint. Both hold a hash of styles, and both can be used inside a value too. See Conditions and breakpoints.

Selectors and at-rules

A key that starts or ends with &, or starts with @, is a selector or an at-rule of its own:

1
<ul class="{{ css({ '& > li': { mt: 'sm' }, '@media print': { display: 'none' } }) }}">

& stands for the element that has the class. Prefer a named condition when one exists: _hover rather than '&:hover'.

Class names

You never write the class names, but you see them in the HTML. A class name is made of the conditions, a short name for the property, and the value:

Style Class name
p: 'md' p_md
padding: 'md' p_md
color: 'blue.500' c_blue.500
_hover: { color: 'primary' } hover:c_primary
md: { p: 'lg' } md:p_lg
w: '[37ch]' w_[37ch]

The same style always gives the same class, in every template, so the CSS file holds each rule once.

The CSS layers

The generated file puts the tokens and the rules in two cascade layers:

1
@layer tokens, utilities;

With the preflight option, it also writes a CSS reset in a reset layer, which comes first:

1
@layer reset, tokens, utilities;

CSS written outside of any layer wins over layered CSS, whatever its specificity. So a rule of your own stylesheet, or of a library such as Bootstrap, overrides a css() class on the same property. To give css() the last word, put your own CSS in layers declared around the ones of the bundle. This follows the layer order of Panda CSS, with components instead of recipes for the CSS of your own components:

1
2
3
4
5
6
/* assets/styles/app.css */
@layer reset, base, tokens, components, utilities;

@layer base {
    a { color: var(--colors-fg); }
}

Layers are ordered by the first place their name appears. A later layer wins over an earlier one. Put this statement at the top of the first stylesheet the page loads, before the css() stylesheet. The statement can list the reset layer even when preflight is off: an unused layer has no effect. For !important declarations, the order is reversed.

Output escaping

css() output is escaped like any other string: a value with special characters cannot break the HTML attribute.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version