Files
gui/apps/gui.hanzo.ai/data/docs/core/create-styled-context.mdx
zeekayandHanzo Dev 69c6e860d7 transplant onto tamagui v2.6.0, brand as a re-runnable transform
This repo could never sync. There was NO merge-base with tamagui — 372 commits
here against 15,791 there, unrelated histories — because it began as a
copy-paste rebrand with a flattened layout. Every "sync" since was a hand
re-application that drifted, which is why the tree sat on 7.3.1 while upstream
shipped fixes we then rediscovered by hand.

This commit's PARENT IS TAMAGUI. A future sync is `git merge tama/main` then
`node scripts/rebrand.mjs` — a real merge, because the history is now shared.

174 packages: 166 upstream, our 8 restored (chrome, shell, telemetry, recipes,
get, font-geist-{sans,mono}, @hanzo/booker), bento-get gained. 170/170 build.

Our patches to files UPSTREAM ALSO OWNS are carried, which the package-level
delta missed and which was where the value actually was:
  - useMedia's server snapshot (`initState ?? getMedia()`). Upstream still
    returns undefined there, so every Tamagui Dialog kills a prerender — the
    exact crash hanzo.app spent a day on.
  - data-slot on web host nodes, absent upstream entirely.
Both applied ONTO upstream's newer files (it rewrote useMedia +150/-63 and
createComponent +160/-55), marked `PATCH (ours, carried across the transplant)`.

Seven traps are encoded in scripts/rebrand.mjs, each found by a gate:
skip itself and lockfiles; special-case the double-branded names in BOTH scoped
and bare form; map path strings, not just paths; drop a level for the flattened
group; check disk rather than a stale index.

Rust build artifacts are NOT committed. An earlier draft of this commit swept
apps/desktop/src-tauri/target/debug in via `git add -A` — 3,859 files including
a 272MB .a, over GitHub's 100MB cap, so the push could never have landed. They
are gitignored now.

Co-Authored-By: Hanzo Dev <[email protected]>
2026-07-30 18:25:06 -07:00

89 lines
2.8 KiB
Plaintext

---
title: createStyledContext
description: Share variant props across compound components
---
When building a "Compound Component API", you need a way to pass properties down to multiple related components at once.
What is a Compound Component API? It looks like this:
```tsx
export default () => (
<Button size="$large">
<Button.Icon>
<Icon />
</Button.Icon>
<Button.Text>Lorem ipsum</Button.Text>
</Button>
)
```
Note how the `size="$large"` is set on the outer Button frame. We'd expect this size property to pass down to both the Icon and Text so that our frame size always matches the icon and text size. It would be cumbersome and bug-prone to have to always pass the size to every sub-component.
Gui solves this with `createStyledContext` which acts much like React `createContext`, except it only works with styled components and only controls their variants (for now, we're exploring if it can do more).
You can set it up as follows:
```tsx
import {
SizeTokens,
View,
Text,
createStyledContext,
styled,
withStaticProperties,
} from '@hanzogui/core'
export const ButtonContext = createStyledContext<{
size: SizeTokens
}>({
size: '$medium',
})
export const ButtonFrame = styled(View, {
name: 'Button',
context: ButtonContext,
variants: {
size: {
'...size': (name, { tokens }) => {
return {
height: tokens.size[name],
borderRadius: tokens.radius[name],
gap: tokens.space[name].val * 0.2,
}
},
},
} as const,
defaultVariants: {
size: '$medium',
},
})
export const ButtonText = styled(Text, {
name: 'ButtonText',
context: ButtonContext,
variants: {
size: {
'...fontSize': (name, { font }) => ({
fontSize: font?.size[name],
}),
},
} as const,
})
export const Button = withStaticProperties(ButtonFrame, {
Props: ButtonContext.Provider,
Text: ButtonText,
})
```
A few things to note here:
- ButtonContext should only be typed and given properties that work across both components. Since they both define a `size` variant, this works.
- But note that one defines `...size` while the other defines `...fontSize`. This works in this case only if your design system has consistent naming for token sizes across `size` and `fontSize` (and is why we highly recommend this pattern).
- You can use `<Button.Props size="$large"><Button /></Button.Props>` now to set default props for a Button from above.
- As of today, using the `context` pattern does not work with the optimizing compiler flattening functionality. We recommend not using this for your most common components like Stacks or Text. For Button or anything higher level it is totally fine - it will still extract CSS and remove some logic from the render function. We have mapped out how this can work with flattening eventually and it should not be too much effort.