Style props
Pass CSS properties as props on styled.* elements. Same atomic CSS as css(), different authoring surface.
Style props are CSS properties on a JSX element. bg="blue.500" is the same atomic CSS as css({ bg: 'blue.500' }).
import { css } from '../styled-system/css'
import { styled } from '../styled-system/jsx'
// className
<button className={css({ bg: 'blue.500', color: 'white', py: '2', px: '4' })} />
// style props
<styled.button bg="blue.500" color="white" py="2" px="4" />css, as, and className are factory props. Variants on styled() are
Styled factory.
You need jsxFramework in your config, or styled-system/jsx is not
generated.
Configure JSX
panda.config.ts
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
jsxFramework: 'react'
})Panda supports React, Preact, Vue 3, Qwik, and Solid. Then run panda codegen.
You can rename the factory with jsxFactory.
Using style props
import { styled } from '../styled-system/jsx'
const Button = ({ children }) => (
<styled.button bg="blue.500" color="white" py="2" px="4" rounded="md">
{children}
</styled.button>
)styled.button is a shorthand for styled('button') when you only need style props.
Factory props
Besides bg and px, the factory reads a few props itself. They are not CSS utilities.
css
An extra style object, merged last among styles. Use it for conditions, selectors, or a style you already have as an object.
<styled.button
bg="blue.500"
css={{
_hover: { bg: 'blue.600' },
'&[data-active]': { bg: 'blue.700' }
}}
>
Click me
</styled.button>One override on a custom component is also css. Named parts use trackCss, slideCss, and so on. See
passing styles to custom components.
className
Appended after the factory classes. Use it for a class you do not control, or a string from outside Panda.
<styled.button bg="blue.500" className="external">
Click me
</styled.button>as
Render a different element. Style props still apply.
<styled.button as="a" href="https://panda-css.com" bg="blue.500">
Docs
</styled.button>HTML attributes
width, height, translate, and content are style props, so they do not reach the DOM. Use the html* aliases
when you need the HTML attribute.
<styled.img htmlWidth="40" htmlHeight="40" src="/logo.png" alt="" />| Prop | Lands on the DOM as |
|---|---|
htmlWidth | width |
htmlHeight | height |
htmlTranslate | translate |
htmlContent | content |
Property names
Extract reads the prop on the tag. circleSize is not size. elementWidth is not width. See
Extraction rules.
styled()
styled() wraps any element or component. The result accepts style props.
import { styled } from '../styled-system/jsx'
import { Button } from 'component-library'
const StyledButton = styled(Button)
<StyledButton bg="blue.500" color="white" py="2" px="4">
Button
</StyledButton>To pass a recipe as the second argument, use Styled factory.
Factory options
The third argument is optional.
interface FactoryOptions<TProps> {
dataAttr?: boolean
defaultProps?: TProps
shouldForwardProp?(prop: string, variantKeys: string[]): boolean
forwardProps?: string[]
}| Option | What it does |
|---|---|
dataAttr | Sets data-recipe={name} when the recipe has a name |
defaultProps | Sit under incoming props, so a caller can still override them |
shouldForwardProp | Decides what reaches the DOM. By default, variants and CSS properties are not forwarded |
forwardProps | Allowlist on top of shouldForwardProp. A forwarded prop no longer feeds the recipe |
const Input = styled('input', {}, { forwardProps: ['size'] })
<Input size={4} />size becomes an HTML attribute. It does not feed a recipe. To keep a key as a variant and pass it through, use
withProvider.
shouldForwardProp
Use a function when the list is not fixed, for example Framer Motion:
import { styled } from '../styled-system/jsx'
import { motion, isValidMotionProp } from 'framer-motion'
const StyledMotion = styled(
motion.div,
{},
{
shouldForwardProp: (prop, variantKeys) =>
isValidMotionProp(prop) || (!variantKeys.includes(prop) && !isCssProperty(prop))
}
)Recipe defaults and unstyled are on Styled factory.
Restricting style props
jsxStyleProps controls which props the factory treats as styles. Default is
all. Tighten it when you do not want bg on every component, or when you want a smaller JSX runtime.
panda.config.ts
export default defineConfig({
jsxStyleProps: 'minimal'
})all
Every style prop. This is the default.
<styled.button bg="blue.500" px="4">
Click me
</styled.button>minimal
The css prop and props that end in Css. bg and px no longer work.
<styled.button css={{ bg: 'blue.500', px: '4' }}>Click me</styled.button>
<Carousel trackCss={{ width: '300px' }} />none
Style props are off. <styled.div /> and styled('div') are invalid. css() and a recipe on styled() still work.
<button className={css({ bg: 'blue.500' })}>Click me</button>
const Button = styled('button', {
base: { bg: 'blue.500' }
})Making your own styled components
splitCssProps pulls style props off a hand-written component.
import { css } from '../styled-system/css'
import { splitCssProps } from '../styled-system/jsx'
import type { HTMLStyledProps } from '../styled-system/types'
export function Component(props: HTMLStyledProps<'div'>) {
const [cssProps, restProps] = splitCssProps(props)
const { css: cssProp, ...styleProps } = cssProps
const className = css({ display: 'flex', height: '20', width: '20' }, styleProps, cssProp)
return <div {...restProps} className={className} />
}
<Component w="2">Click me</Component>TypeScript
Style object
JsxStyleProps is the style-object shape.
import type { JsxStyleProps } from '../styled-system/types'
interface ButtonProps {
color?: JsxStyleProps['color']
}Style props
HTMLStyledProps is the element plus style props.
import type { HTMLStyledProps } from '../styled-system/jsx'
type ButtonProps = HTMLStyledProps<'button'>Variant props
StyledVariantProps reads variants off a styled() component.
import { styled } from '../styled-system/jsx'
import type { StyledVariantProps } from '../styled-system/jsx'
const Button = styled('button', {
base: { color: 'black' },
variants: {
state: {
error: { color: 'red' },
success: { color: 'green' }
}
}
})
type ButtonVariantProps = StyledVariantProps<typeof Button>
// { state?: 'error' | 'success' | undefined }Patterns
Each pattern has a matching props type.
import type { StackProps } from '../styled-system/jsx'