Skip to content

Commit ba2c05a

Browse files
committed
docs: style-context
1 parent d236e21 commit ba2c05a

File tree

2 files changed

+212
-1
lines changed

2 files changed

+212
-1
lines changed

website/pages/docs/concepts/_meta.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
"recipes": "Recipes",
1111
"slot-recipes": "Slot Recipes",
1212
"style-props": "JSX Style Props",
13+
"jsx-style-context": "JSX Style Context",
1314
"color-opacity-modifier": "Color opacity modifier",
1415
"hooks": "Hooks",
1516
"styled-system": "Styled System",
1617
"extend": "The extend keyword"
17-
}
18+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
---
2+
title: JSX Style Context
3+
description: JSX Style Context provides an ergonomic way to style compound components with slot recipes.
4+
---
5+
6+
# JSX Style Context
7+
8+
JSX Style Context is a powerful feature that allows you to create compound components from slot recipes.
9+
10+
It uses a context-based approach to distribute recipe styles across multiple child components, making it easier to style headless UI libraries like Ark UI, and Radix UI.
11+
12+
## Atomic Slot Recipe
13+
14+
- Create a slot recipe using the `sva` function
15+
- Pass the slot recipe to the `createStyleContext` function
16+
- Use the `withProvider` and `withContext` functions to create compound components
17+
18+
```tsx
19+
// components/ui/card.tsx
20+
21+
import { sva } from 'styled-system/css'
22+
import { createStyleContext } from 'styled-system/jsx'
23+
24+
const card = sva({
25+
slots: ['root', 'label'],
26+
base: {
27+
root: {},
28+
label: {}
29+
},
30+
variants: {
31+
size: {
32+
sm: { root: {} },
33+
md: { root: {} }
34+
}
35+
},
36+
defaultVariants: {
37+
size: 'sm'
38+
}
39+
})
40+
41+
const { withProvider, withContext } = createStyleContext(card)
42+
43+
const Root = withProvider('div', 'root')
44+
const Label = withContext('label', 'label')
45+
46+
export const Card = {
47+
Root,
48+
Label
49+
}
50+
```
51+
52+
Then you can use the `Root` and `Label` components to create a card.
53+
54+
```tsx
55+
// app/page.tsx
56+
57+
import { Card } from './components/ui/card'
58+
59+
export default function App() {
60+
return (
61+
<Card.Root>
62+
<Card.Label>Hello</Card.Label>
63+
</Card.Root>
64+
)
65+
}
66+
```
67+
68+
## Config Slot Recipe
69+
70+
The `createStyleContext` function can also be used with slot recipes defined in the `panda.config.ts` file.
71+
72+
- Pass the config recipe to the `createStyleContext` function
73+
- Use the `withProvider` and `withContext` functions to create compound components
74+
75+
```tsx
76+
// components/ui/card.tsx
77+
78+
import { card } from '../styled-system/recipes'
79+
import { createStyleContext } from 'styled-system/jsx'
80+
81+
const { withProvider, withContext } = createStyleContext(card)
82+
83+
const Root = withProvider('div', 'root')
84+
const Label = withContext('label', 'label')
85+
86+
export const Card = {
87+
Root,
88+
Label
89+
}
90+
```
91+
92+
Then you can use the `Root` and `Label` components to create a card.
93+
94+
```tsx
95+
// app/page.tsx
96+
97+
import { Card } from './components/ui/card'
98+
99+
export default function App() {
100+
return (
101+
<Card.Root>
102+
<Card.Label>Hello</Card.Label>
103+
</Card.Root>
104+
)
105+
}
106+
```
107+
108+
## createStyleContext
109+
110+
This function is a factory function that returns three functions: `withRootProvider`, `withProvider`, and `withContext`.
111+
112+
### withRootProvider
113+
114+
Creates the root component that provides the style context. Use this when the root component **does not render an underling DOM element**.
115+
116+
```tsx
117+
import { Dialog } from '@ark-ui/react'
118+
119+
//...
120+
121+
const DialogRoot = withRootProvider(Dialog.Root)
122+
```
123+
124+
### withProvider
125+
126+
Creates a component that both provides context and applies the root slot styles. Use this when the root component **renders an underling DOM element**.
127+
128+
> **Note:** It requires the root `slot` parameter to be passed.
129+
130+
```tsx
131+
import { Avatar } from '@ark-ui/react'
132+
133+
//...
134+
135+
const AvatarRoot = withProvider(Avatar.Root, 'root')
136+
```
137+
138+
### withContext
139+
140+
Creates a component that consumes the style context and applies slot styles. It does not accept variant props directly, but gets them from context.
141+
142+
```tsx
143+
import { Avatar } from '@ark-ui/react'
144+
145+
//...
146+
147+
const AvatarImage = withContext(Avatar.Image, 'image')
148+
const AvatarFallback = withContext(Avatar.Fallback, 'fallback')
149+
```
150+
151+
### unstyled prop
152+
153+
Every component created with `createStyleContext` supports the `unstyled` prop to disable styling. It is useful when you want to opt-out of the recipe styles.
154+
155+
- When applied the root component, will disable all styles
156+
- When applied to a child component, will disable the styles for that specific slot
157+
158+
```tsx
159+
// Removes all styles
160+
<AvatarRoot unstyled>
161+
<AvatarImage />
162+
<AvatarFallback />
163+
</AvatarRoot>
164+
165+
// Removes only the styles for the image slot
166+
<AvatarRoot>
167+
<AvatarImage unstyled css={{ bg: 'red' }} />
168+
<AvatarFallback />
169+
</AvatarRoot>
170+
```
171+
172+
## Guides
173+
174+
### Config Recipes
175+
176+
The rules of config recipes still applies when using `createStyleContext`. Ensure the name of the final component matches the name of the recipe.
177+
178+
> If you want to use a custom name, you can configure the recipe's `jsx` property in the `panda.config.ts` file.
179+
180+
```tsx
181+
// recipe name is "card"
182+
import { card } from '../styled-system/recipes'
183+
184+
const { withRootProvider, withContext } = createStyleContext(card)
185+
186+
const Root = withRootProvider('div')
187+
const Header = withContext('header', 'header')
188+
const Body = withContext('body', 'body')
189+
190+
// The final component name must be "Card"
191+
export const Card = {
192+
Root,
193+
Header,
194+
Body
195+
}
196+
```
197+
198+
### Default Props
199+
200+
Use `defaultProps` option to provide default props to the component.
201+
202+
```tsx
203+
const { withContext } = createStyleContext(card)
204+
205+
export const CardHeader = withContext('header', 'header', {
206+
defaultProps: {
207+
role: 'banner'
208+
}
209+
})
210+
```

0 commit comments

Comments
 (0)