Files
zeekayandHanzo Dev 751ef5c778 rename the framework to @hanzo/gui and the loader to @hanzogui/loader
Both old names are owned by a different npm account (artemis-prime), so
publishing them returns 403 — which is how this surfaced: the 8.0.0 run
shipped @hanzogui/logo and @hanzogui/demos depending on [email protected], a
version that cannot be published and therefore does not exist. Those two
were uninstallable.

@hanzo/gui and @hanzogui/* are ours, so the framework now carries the name
it is imported by everywhere downstream, and the loader moves under the
scope we control.

The rewrite is limited to package references. `DEBUG?.startsWith('hanzogui')`
is a log-namespace filter and join(dir, 'hanzogui') is a path — rewriting
either would change behaviour, so both are untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 20:23:18 -07:00

101 lines
3.6 KiB
Plaintext

---
title: useMedia
description: Respond to different screen sizes
---
Define your media rules in the media object of your `hanzogui.config.ts`:
```tsx line=2-6
export default createGui({
media: {
xs: { maxWidth: 660 },
gtXs: { minWidth: 660 + 1 },
sm: { maxWidth: 860 },
gtSm: { minWidth: 860 + 1 },
md: { maxWidth: 980 },
gtMd: { minWidth: 980 + 1 },
lg: { maxWidth: 1120 },
gtLg: { minWidth: 1120 + 1 },
short: { maxHeight: 820 },
tall: { minHeight: 820 },
hoverNone: { hover: 'none' },
touch: { pointer: 'coarse' },
},
})
```
<Notice theme="blue">
Choose the naming convention you prefer. We use `sm`, `md`, `lg` and `gtSm` etc. Where
"gt" means "greater than".
</Notice>
The order here is important: items defined further down will override items before. In this example, `xs` is the weakest, `gtXs` will override it, and so on.
Behind the scenes, we convert this object syntax into media query syntax with a simple loop over your object, turning camelCase into hyphen-case, and adding `@media()` around it.
### Usage
Now in any component you may import and use `useMedia` or `$` prefixed media prop styles.
### Inline props
```tsx
import { Button, XStack, useMedia } from '@hanzo/gui' // note: design system can use @hanzogui/core
export default () => {
const [x, setX] = useState(0)
return (
<XStack
backgroundColor="red"
$gtSm={{
backgroundColor: 'blue',
}}
$gtMd={{
backgroundColor: x > 0.5 ? 'green' : 'yellow',
}}
>
<Button onPress={() => setX(Math.random())}>Hello</Button>
</XStack>
)
}
```
In this example we are doing mobile-first design, where the base props will be overridden as the viewport gets wider. Notice the ternary logic in `$gtMd`: this is extractable with Gui, and will still output simple CSS with no leftover style props in your component's render function.
### Hooks
```tsx
import { Button, XStack, useMedia } from '@hanzo/gui' // note: design system can use @hanzogui/core
export default () => {
const media = useMedia()
return (
<XStack
// can be used as a ternary
backgroundColor={media.sm ? 'red' : 'blue'}
// can be used as a spread
{...(media.lg && {
x: 10,
y: 10,
})}
>
<Button>Hello</Button>
</XStack>
)
}
```
As long as **all** of your usages of useMedia are extractable, Gui will actually generate your CSS and then fully remove the hook from the output code. You can check this by adding `// debug` to the top of your component.
Of course, you may sometimes use `useMedia` for other purposes than styling. In fact, that's the nice part about Gui - if it can't extract, it always falls back to runtime gracefully.
Gui runtime `useMedia` usage will track which keys are accessed, and only update if the media query matching that key updates. This granular updating is nice for performance.
#### Limitations
The `useMedia` hook uses proxies so it can track which keys you are accessing and only re-render components that need re-rendering based on those keys. The Gui compiler also understands straightforward uses of the hook during compile-time and can remove it entirely when targeting the web, in favor of CSS.
- In order to keep things lightweight and simple, the proxied object returned by `useMedia` is not iterable, and you can't check keys on it using `in` or get them using `Object.keys`.
- It's encouraged to write `const media = useMedia()` and then access your keys like `media.sm` to work best with the compiler. The compiler supports de-structuring, but not re-naming.