mirror of
https://github.com/hanzoai/gui.git
synced 2026-10-25 02:31:41 +00:00
700 lines
28 KiB
Plaintext
700 lines
28 KiB
Plaintext
---
|
|
title: Gui 2
|
|
publishedAt: '2025-12-29'
|
|
description: More stable, easy, documented, fast, and feature-complete.
|
|
by: nate
|
|
image: /blog/version-two.jpg
|
|
---
|
|
|
|
<IntroParagraph large>
|
|
Gui brings high performing, consistent, typed inline styles to React Native and React
|
|
Web, plus composable UI components, a novel theme system and an optimizing compiler.
|
|
</IntroParagraph>
|
|
|
|
We're excited to announce **the first release candidate for Gui v2 is
|
|
here**!
|
|
|
|
We'll do a little housekeeping first, so if you want to,
|
|
[skip to what's new](#new-in-v2).
|
|
|
|
### What makes it great
|
|
|
|
Gui brings many style features from CSS to native. Every style it supports
|
|
works on both native and web, at both run-time and compile-time, and server-side
|
|
as well as client-side.
|
|
|
|
In comparison to other solutions, Gui is especially strong at:
|
|
|
|
- **Many features, high performance everywhere.** Other solutions prioritize one
|
|
platform, and bail out of the hard parts of web performance that require a
|
|
compiler _and_ a lot of careful work to get right. Some examples of large
|
|
areas Gui does well - SSR safe spring animations, SSR safe light-dark
|
|
themes, SSR safe media queries and Container all the above features working
|
|
with CSS or springs, and so on.
|
|
- **Top tier performance everywhere.** A small example - you can choose from 4
|
|
animation drivers (CSS, Reanimated, Motion, React Native), per-platform, yet
|
|
no matter which you choose you get proper SSR support—even media queries and
|
|
dark mode render and hydrate without jumps or flickers.
|
|
- **Type-safe inline styling that merges and optimizes.** Inline styles are
|
|
productivity boosts, but Gui adds type safety, easy/controllable merging,
|
|
and an optimizing compiler that does partial analysis to optimize even
|
|
logic-filled styling. It's an underrated boost to productivity.
|
|
- **Refined, styled and unstyled composable components.** Great on web and
|
|
native thanks to composable components, native adaptation, the Adapt
|
|
primitive, and a lot of iteration.
|
|
- **Robust.** Gui has been developed actively for years, proven in
|
|
[large apps](https://uniswap.org), and has more than tripled test coverage
|
|
just in the last year.
|
|
|
|
### During v1
|
|
|
|
- **8,500+ commits** over 2 years (~330/month).
|
|
- **900+ issues closed**.
|
|
- **136 new contributors** (from 46 to 182 total).
|
|
- **289 test files** with kitchen-sink tests running across all 4 animation
|
|
drivers, plus many new deeper native integration tests with both Detox and
|
|
Maestro.
|
|
- Released
|
|
[`@hanzogui/build`](https://github.com/hanzoai/gui/blob/v2/pkgs/build/README.md),
|
|
which makes it trivial to publish npm packages that support CommonJS and
|
|
ESModules, native and web without requiring any configuration at all when
|
|
importing - whether it's Metro, Node, Vite, or otherwise.
|
|
- Platform, theme, and container queries, plus combined container and media
|
|
queries.
|
|
- New compound components [Tabs](/docs/components/tabs),
|
|
[Accordion](/docs/components/accordion),
|
|
[ToggleGroup](/docs/components/toggle-group).
|
|
- New unstyled versions of most components.
|
|
- A lot of low level work on performance, documentation, our CLI, and more.
|
|
- Improved theme generation packages, and the powerful
|
|
[free and paid theme builder](/theme).
|
|
|
|
[](/theme/37/nike-neon)
|
|
|
|
## New in v2
|
|
|
|
Version 2 is a huge release but the migration from v1 should only be moderate.
|
|
We removed mostly deprecated APIs, aligned to web and modern React Native,
|
|
improved performance and native library integrations, and dropped a few new
|
|
features and components.
|
|
|
|
Find a [list of breaking changes at the bottom of the post](#breaking-changes).
|
|
|
|
<Notice>Give this blog post URL to your favorite coding agent to help upgrade!</Notice>
|
|
|
|
### Features
|
|
|
|
#### Config v5
|
|
|
|
The default Gui configuration has been upgraded to v5 with a more complete
|
|
design system and easier customization. See the
|
|
[Config v5 docs](/docs/core/config-v5) for full details.
|
|
|
|
**More color themes** - V5 adds gray, orange, pink, purple, teal, and neutral to
|
|
the existing blue, red, yellow, and green palettes, all using Radix Colors v3
|
|
for improved accessibility.
|
|
|
|
**Opacity tokens** - New foreground and background opacity variants make subtle
|
|
overlays and borders easy: `$color01`, `$color0075`, `$color005`,
|
|
`$background01`, and more.
|
|
|
|
**Shadow colors** - Pre-tuned shadow opacities (`$shadow1` through `$shadow6`)
|
|
that work well in both light and dark modes.
|
|
|
|
**Expanded media queries** - Height-based queries (`$height-xs`, `$height-sm`,
|
|
etc.), a `$pointerTouch` query for touch detection, and renamed size queries
|
|
(`$xxl`, `$xxs`, `$xxxs`). The `$sm` through `$xxl` breakpoints now match
|
|
Tailwind CSS exactly (640, 768, 1024, 1280, 1536), making it easier to work
|
|
across both ecosystems. The smaller breakpoints (`$xxxs`, `$xxs`, `$xs`) are
|
|
designed for container queries where you need finer control below 640px.
|
|
|
|
**Easy customization** - The new `createV5Theme` helper lets you add or override
|
|
color themes with minimal boilerplate, working directly with `@hanzogui/colors`.
|
|
|
|
**Subtle variant** - Import from `@hanzogui/config/v5-subtle` for a more muted,
|
|
desaturated color palette. Or use `adjustPalette` and `adjustPalettes` to create
|
|
your own custom color transformations.
|
|
|
|
#### New Styles
|
|
|
|
See the [Style API docs](/docs/intro/styles) for the full reference, some
|
|
highlights:
|
|
|
|
- **`backgroundImage`** - CSS `linear-gradient` and `radial-gradient` syntax
|
|
with token support.
|
|
- **`boxShadow`** - Full CSS box-shadow support including multiple shadows,
|
|
spread, and inset. Accepts strings with your tokens.
|
|
- **`filter`** - Graphical filters like `brightness`, `opacity`, `blur`.
|
|
- **`mixBlendMode`** - Blend modes like `multiply`, `screen`, `overlay`, etc.
|
|
- **`isolation`** - Creates a new stacking context (`auto` | `isolate`)
|
|
- **`boxSizing`** - Box model (`border-box` | `content-box`).
|
|
- **`display`** - Pass-through with `contents`.
|
|
- **`position`** - Now accepts `fixed`, automatically converted to `absolute` on
|
|
native. For easier media queries like `$md={{ position: 'fixed' }}`.
|
|
- **`borderCurve`** - Corner curve style (`circular` | `continuous` for Apple's
|
|
"squircle"). iOS 13+ only.
|
|
- **`cursor`** - Cursor style. Full CSS values on web; `auto` | `pointer` on iOS
|
|
17+ (trackpad/stylus).
|
|
- **`textShadow`** - CSS text-shadow shorthand with token support:
|
|
`textShadow="2px 2px 4px $shadowColor"`. On native, only single shadows
|
|
supported.
|
|
- **`border`** - CSS border shorthand with token support:
|
|
`border="1px solid $borderColor"`. On native, expands to individual width,
|
|
style, and color properties.
|
|
- **`outline`** - CSS outline shorthand with token support:
|
|
`outline="2px solid $outlineColor"`. On native, expands to `outlineWidth`,
|
|
`outlineStyle`, and `outlineColor`.
|
|
|
|
### New Components
|
|
|
|
#### Menu
|
|
|
|
[Menu](/docs/components/menu) provides dropdown menus with full keyboard
|
|
navigation, submenus, checkbox items, and animations. On iOS and Android, it
|
|
automatically renders using native platform menus.
|
|
|
|
<HeroContainer>
|
|
<MenuDemo />
|
|
</HeroContainer>
|
|
|
|
```tsx hero template=Menu
|
|
|
|
```
|
|
|
|
#### ContextMenu
|
|
|
|
[ContextMenu](/docs/components/context-menu) works like Menu but activates on
|
|
right-click (web) or long-press (native). It includes support for preview
|
|
content on iOS.
|
|
|
|
<HeroContainer>
|
|
<ContextMenuDemo />
|
|
</HeroContainer>
|
|
|
|
```tsx hero template=ContextMenu
|
|
|
|
```
|
|
|
|
#### Input & TextArea
|
|
|
|
<HeroContainer demoMultiple>
|
|
<NewInputsDemo />
|
|
</HeroContainer>
|
|
|
|
```tsx hero template=Inputs
|
|
|
|
```
|
|
|
|
Input has been rewritten from scratch with a web-first approach - you write
|
|
standard HTML input attributes and Gui automatically converts them to React
|
|
Native equivalents on native platforms:
|
|
|
|
```tsx
|
|
// Web-standard API that works everywhere
|
|
<Input type="email" enterKeyHint="send" />
|
|
<Input type="password" />
|
|
<Input type="tel" />
|
|
```
|
|
|
|
This replaces the React Native-style props like `keyboardType`,
|
|
`secureTextEntry`, and `returnKeyType` with their web equivalents. The old props
|
|
still work but are deprecated. See the [Input docs](/docs/components/inputs) for
|
|
the full migration guide.
|
|
|
|
#### Image
|
|
|
|
The [Image](/docs/components/image) component follows the same web-first
|
|
philosophy as Input. It uses standard HTML `<img>` attributes like `src`, `alt`,
|
|
`loading`, and `decoding` as the primary API, with automatic conversion to React
|
|
Native equivalents on native.
|
|
|
|
On native, you can choose your image loading adapter - use the built-in React
|
|
Native Image, or integrate with optimized libraries like `expo-image` or
|
|
`react-native-fast-image` for better caching and performance.
|
|
|
|
#### Sheet, Button, ListItem, Select
|
|
|
|
All were re-written internally to retain much the same API surface, but align
|
|
better to the web, and run dramatically faster and better.
|
|
|
|
Select on web and Sheet on native got big upgrades.
|
|
|
|
### Motion Animation Driver
|
|
|
|

|
|
|
|
The all powerful [Motion animation library](https://motion.dev) comes to Gui
|
|
as an [animation driver](/docs/core/animations-motion), bringing real innovation
|
|
to web aimations.
|
|
|
|
The driver is still somewhat experimental, we're still working through some very
|
|
subtle issues with sending updates rapidly, and are working them to isolate it.
|
|
|
|
What makes this even more interesting is that Gui completely re-wrote the
|
|
internal component logic to allow a new `avoidReRenders` path option for
|
|
animation drivers. When true, all group, media, pseudo, and some theme styles
|
|
all move out of React.
|
|
|
|
Combined with Motion's support of the off-thread
|
|
[Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API),
|
|
and it makes for really incredibly smooth feeling apps.
|
|
|
|
We noticed a large gain in performance in a large app by just swapping to the
|
|
driver, and the animations feel great — see them for yourself on this site. Just
|
|
note, there's a can be occasionally hiccups with some enter styles. There's a
|
|
way to work around this, but then you de-opt other parts. We're sure we'll get
|
|
Motion out of beta soon, and even in it's current state it's worth considering.
|
|
|
|
### Reanimated Driver
|
|
|
|
The [Reanimated](https://docs.swmansion.com/react-native-reanimated/) driver
|
|
comes back in style with `worklet` and `avoidReRenders` support. This means
|
|
animations run entirely on the UI thread without triggering React re-renders,
|
|
giving you much better performance for complex animations on both web and
|
|
native.
|
|
|
|
The Moti driver (`@hanzogui/animations-moti`) is now deprecated in favor of the
|
|
[Reanimated driver](/docs/core/animations-reanimated)
|
|
(`@hanzogui/animations-reanimated`). This removes a dependency and fixes some
|
|
compatibility issues. If you're using `@hanzogui/animations-moti`, switch to
|
|
`@hanzogui/animations-reanimated` - the API is the same.
|
|
|
|
#### Swap Animation Drivers Inline
|
|
|
|
You can now configure multiple animation drivers and select per-component using
|
|
the new `animatedBy` prop. This serves two important purposes: it allows mixing
|
|
drivers more granularly, and it enables the compiler to better optimize. See the
|
|
[animation drivers docs](/docs/core/animation-drivers#multiple-drivers) for full
|
|
details.
|
|
|
|
```tsx
|
|
// Config with multiple drivers up front
|
|
createGui({
|
|
animations: {
|
|
default: cssDriver,
|
|
spring: reanimatedDriver,
|
|
},
|
|
})
|
|
|
|
// Select per-component - compiler can optimize knowing the driver
|
|
<View animatedBy="spring" transition="bouncy" />
|
|
```
|
|
|
|
The compiler can optimize better with this pattern, and you can now lazy load a
|
|
driver with a function:
|
|
|
|
```tsx
|
|
import { loadAnimationDriver } from '@hanzo/gui'
|
|
loadAnimationDriver('spring', reanimatedDriver)
|
|
```
|
|
|
|
#### Transition Delay
|
|
|
|
All animation drivers now support delays:
|
|
|
|
```tsx
|
|
<View transition={['bouncy', { delay: 200 }]} />
|
|
```
|
|
|
|
This works with CSS, React Native Animated, Reanimated, and Motion drivers.
|
|
|
|
#### Enter/Exit Transition Control
|
|
|
|
The `transition` prop now supports different animations for enter and exit. This
|
|
is useful for creating asymmetric animations where elements enter slowly but
|
|
exit quickly, or vice versa:
|
|
|
|
```tsx
|
|
// slow enter, fast exit
|
|
<View
|
|
transition={{ enter: 'lazy', exit: 'quick' }}
|
|
enterStyle={{ opacity: 0 }}
|
|
exitStyle={{ opacity: 0 }}
|
|
/>
|
|
|
|
// with a default for property changes while mounted
|
|
<View
|
|
transition={{ enter: 'lazy', exit: 'quick', default: 'bouncy' }}
|
|
/>
|
|
|
|
// array syntax with delay and per-property config
|
|
<View
|
|
transition={['bouncy', { enter: 'lazy', exit: 'quick', delay: 200 }]}
|
|
/>
|
|
```
|
|
|
|
This works on all four animation drivers. See the
|
|
[animation docs](/docs/core/animations#enterexittransitions) for more details.
|
|
|
|
#### Pseudo-Style Transitions
|
|
|
|
Pseudo-style props (`hoverStyle`, `pressStyle`, `focusStyle`) now support their
|
|
own `transition` property. This enables CSS-like semantics where entering a
|
|
state uses that state's transition, and exiting uses the base transition:
|
|
|
|
```tsx
|
|
<Square
|
|
transition="1000ms" // slow exit (back to base)
|
|
hoverStyle={{
|
|
transition: '200ms', // fast enter
|
|
backgroundColor: 'red',
|
|
}}
|
|
/>
|
|
```
|
|
|
|
This pattern creates snappy, responsive interactions where elements react
|
|
quickly to user input but settle back smoothly. Works with group pseudo states
|
|
too (`$group-card-hover`). See the
|
|
[animation docs](/docs/core/animations#pseudo-style-transitions) for details.
|
|
|
|
#### Popover `transform-origin`
|
|
|
|
[Popover](/docs/components/popover) and [Tooltip](/docs/components/tooltip) now
|
|
automatically calculate the correct CSS `transform-origin` based on placement
|
|
and arrow position. This means scale animations naturally "grow" from the anchor
|
|
point where the content connects to the trigger.
|
|
|
|
The transform origin adjusts automatically based on the final placement - if the
|
|
popover flips from `bottom` to `top`, the origin updates accordingly. This
|
|
creates polished, native-feeling animations without any manual configuration.
|
|
|
|
#### Consistent Active Styling
|
|
|
|
Components with toggle/selection states now support consistent `activeStyle` and
|
|
`activeTheme` props for styling their active states:
|
|
|
|
- [**Switch**](/docs/components/switch) - Styles applied when the switch is on
|
|
- [**Checkbox**](/docs/components/checkbox) - Styles applied when checked
|
|
- [**ToggleGroup.Item**](/docs/components/toggle-group) - Styles applied when
|
|
the item is selected
|
|
- [**Tabs.Tab**](/docs/components/tabs) - Styles applied when the tab is active
|
|
|
|
```tsx
|
|
// Apply custom styles when active
|
|
<Switch activeStyle={{ backgroundColor: '$green8' }} />
|
|
|
|
// Or apply a theme when active
|
|
<Checkbox activeTheme="green" />
|
|
|
|
// Works inline or via styled()
|
|
const GreenTab = styled(Tabs.Tab, {
|
|
activeStyle: {
|
|
backgroundColor: '$green9',
|
|
},
|
|
})
|
|
```
|
|
|
|
This replaces a variety of inconsistent APIs in v1.
|
|
|
|
#### Faster, Lighter, more Consistent Components
|
|
|
|
Several components have been significantly simplified:
|
|
|
|
[**Button**](/docs/components/button) - Rewritten from scratch with ~60% less
|
|
code. No longer uses the slow `useProps` hook internally. Now supports all
|
|
web-standard HTML button attributes (`type`, `formAction`, `formMethod`, `name`,
|
|
`value`, `popoverTarget`, etc.). Defaults to `type="button"` to prevent
|
|
accidental form submissions.
|
|
|
|
[**ListItem**](/docs/components/list-item) - Rebuilt with context-based styling.
|
|
Removed text style props (`fontFamily`, `fontSize`, etc.) and internal spacing
|
|
props (`spaceFlex`, `scaleSpace`) for composable component API. Much faster
|
|
rendering.
|
|
|
|
[**Select**](/docs/components/select) - SelectItem is based on ListItem so is
|
|
likewise much faster, and gains an optional floating indicator. SelectLabel is
|
|
now a simpler SizableText-based component instead of depending on ListItem.
|
|
|
|
**Icons** - Themed icons now use a fast path that skips the heavy style
|
|
resolution when no media queries are used, significantly reducing re-renders in
|
|
apps with many icons.
|
|
|
|
[**Progress**](/docs/components/progress) - Now SSR-friendly with
|
|
percentage-based transforms on web that render correctly without client-side
|
|
hydration. Bouncy animations no longer overshoot past the container edges.
|
|
|
|
[**Tabs**](/docs/components/tabs) - `activeStyle` and `activeTheme` props
|
|
replace the old `Theme` wrapper approach. `activationMode` now defaults to
|
|
`'manual'` (click/Enter to activate) matching web standards.
|
|
|
|
[**Group**](/docs/components/group) - Dramatically simplified. No more magic
|
|
child cloning.
|
|
|
|
#### Headless and Unstyled Components
|
|
|
|
We're expanding headless components in v2. Many components now have three
|
|
variants:
|
|
|
|
- **Styled** - Full Gui components with default styles
|
|
- **Unstyled** - Uses a `createX` factory allowing fully custom styling
|
|
- **Headless** - Zero dependency on `@hanzogui/core`, just hooks
|
|
|
|
The headless packages (`@hanzogui/switch-headless`, `@hanzogui/checkbox-headless`,
|
|
`@hanzogui/radio-headless`, `@hanzogui/tabs-headless`) provide hooks like
|
|
`useSwitch`, `useCheckbox`, `useRadioGroup`, and `useTabs` that handle all the
|
|
state management, accessibility, and keyboard navigation - letting you bring
|
|
your own styling solution.
|
|
|
|
This makes Gui components usable even if you're not using Gui for
|
|
styling. For now it's a subset, but we plan to continue expanding headless
|
|
exports throughout v2.
|
|
|
|
#### @hanzogui/react-native-web-lite
|
|
|
|
React Native Web has slowed down development and has various issues in modern JS
|
|
projects. We built `@hanzogui/react-native-web-lite` by translating
|
|
`react-native-web` to TypeScript, moving to a modern ESModule setup, and
|
|
enabling tree shaking.
|
|
|
|
If you're using Gui for most styling, you can save a significant amount of
|
|
bundled JS on web by aliasing to this package. It's not perfectly compatible
|
|
with `react-native-web` - it strips out the style system to share Gui
|
|
internals - but for Gui-first apps, it's a nice optimization.
|
|
|
|
#### Component Scope
|
|
|
|
[Dialog](/docs/components/dialog), [Popover](/docs/components/popover),
|
|
[Sheet](/docs/components/sheet), and [Tooltip](/docs/components/tooltip) now
|
|
support a `scope` prop that lets you mount a single instance at your app's root
|
|
while placing triggers anywhere in your tree. **This is a significant
|
|
performance win** - in testing with large apps, we found it greatly improved UX
|
|
by eliminating the overhead of mounting full overlay components inline.
|
|
|
|
Instead of each Tooltip or Popover in a list rendering its own portal, content,
|
|
and animation logic, you mount one instance at the root and scatter lightweight
|
|
triggers throughout your app. The triggers are just simple components that
|
|
communicate with the shared instance via context.
|
|
|
|
```tsx
|
|
// _layout.tsx - mount once at root with your providers
|
|
<GuiProvider>
|
|
<Tooltip scope="global">
|
|
<Tooltip.Content>
|
|
<Tooltip.Arrow />
|
|
<Paragraph>{/* label set by trigger */}</Paragraph>
|
|
</Tooltip.Content>
|
|
|
|
{/* rest of your app */}
|
|
<Slot />
|
|
</Tooltip>
|
|
</GuiProvider>
|
|
|
|
// anywhere in your app - just the trigger
|
|
<Tooltip.Trigger scope="global" aria-label="Settings">
|
|
<Button icon={Settings} />
|
|
</Tooltip.Trigger>
|
|
```
|
|
|
|
This pattern is especially valuable for data-heavy views like tables, lists, or
|
|
dashboards where you might have dozens or hundreds of interactive elements that
|
|
need tooltips or popovers.
|
|
|
|
### New Colors
|
|
|
|
`@hanzogui/colors` has been updated to Radix v3, old colors are available at
|
|
`@hanzogui/colors/legacy`. See the [Colors docs](/docs/intro/colors) for full
|
|
details.
|
|
|
|
### Compiler Improvements
|
|
|
|
The [compiler](/docs/intro/compiler-install) has been significantly improved in
|
|
v2, especially for native. Most notably, the experimental theme optimization
|
|
setting is now on by default, and stable. This means better performance on
|
|
native without any configuration needed.
|
|
|
|
### Native Portals
|
|
|
|
Gui's portal-based components (Sheet, Dialog, Popover, Select, and Toast)
|
|
now support true native portals via
|
|
[react-native-teleport](https://github.com/nicksrandall/react-native-teleport).
|
|
|
|
Native doesn't support portals. Gui v1 worked around this by abusing private
|
|
APIs and automatically re-propagating its own contexts, but your custom contexts
|
|
would break. This also added lots of overhead.
|
|
|
|
In v2 you can now add `react-native-teleport`, then import:
|
|
|
|
```tsx
|
|
import '@hanzogui/native/setup-teleport'
|
|
```
|
|
|
|
Now all components that portal work better and faster. See the
|
|
[Portal docs](/docs/components/portal) for details and alternative approaches
|
|
like component scoping.
|
|
|
|
### Native Sheet Gestures
|
|
|
|
[Sheet](/docs/components/sheet) now has optional integration with
|
|
`react-native-gesture-handler` for much smoother performance on native. Install
|
|
`react-native-gesture-handler` and add the setup import before any Gui
|
|
imports.
|
|
|
|
See the [`@hanzogui/native` docs](/ui/native) or
|
|
[Sheet docs](/docs/components/sheet) for full details.
|
|
|
|
### Cross-Platform Pointer Events
|
|
|
|
Pointer events (`onPointerDown`, `onPointerUp`, `onPointerMove`,
|
|
`onPointerEnter`, `onPointerLeave`, `onPointerCancel`) now work cross-platform.
|
|
On native, they're mapped to touch events with a normalized event shape matching
|
|
the web API: The `setPointerCapture` and `releasePointerCapture` APIs are
|
|
supported for drag scenarios where you need move events to continue firing even
|
|
after the pointer leaves the element bounds.
|
|
|
|
### CLI Improvements and Agent Prompt Generation
|
|
|
|
The [Gui CLI](/docs/guides/cli) has new commands for building and working
|
|
with your design system:
|
|
|
|
- **`hanzogui build`** - Pre-compile components in-place for production. Works
|
|
with any bundler and supports wrapping your build command to automatically
|
|
restore files after.
|
|
- **`hanzogui generate`** - Build your full Gui configuration and output CSS.
|
|
Validates your config and pre-generates your design system.
|
|
- **`hanzogui generate-css`** - Generate the `hanzogui.generated.css` file from your config.
|
|
Use `--output` to specify a custom output path.
|
|
- **`hanzogui generate-prompt`** - Generate an LLM-friendly markdown file from
|
|
your config, documenting all tokens, themes, components, and shorthands for
|
|
use with AI assistants.
|
|
- **`hanzogui check`** - Scan for inconsistent dependency versions across your
|
|
project.
|
|
|
|
We recommend generating your prompt and committing to your repo, even before you
|
|
do your full upgrade to version 2, as it will help agents understand your
|
|
Gui config better.
|
|
|
|
### Smaller Bundle Size
|
|
|
|
The `@hanzogui/core` bundle has been reduced by ~32% (from ~37KB to ~25KB
|
|
gzipped). This was achieved through several optimizations to color parsing,
|
|
expensive gesture handling, and automatically trimming optional theme generation
|
|
code.
|
|
|
|
### Breaking Changes
|
|
|
|
- **Shadow colors** output opacities using `color-mix()` which may break
|
|
snapshot tests or any code testing the expected parsed format.
|
|
- **Removed `@hanzogui/react-native-use-responder-events`.** If you were using
|
|
`onResponderGrant`, `onResponderMove`, `onResponderRelease`, or
|
|
`onResponderTerminate` props on web, switch to standard pointer events
|
|
(`onPointerDown`, `onPointerMove`, `onPointerUp`) or touch events. On native,
|
|
use React Native's built-in responder system.
|
|
- **Config v5 changes from v4.** Media query names change (`2xl` → `xxl`, `2xs`
|
|
→ `xxs`), style defaults align with React Native. See
|
|
[Config v5 docs](/docs/core/config-v5).
|
|
- **React Native 0.81+, React 19+, and TypeScript 5+ required.** Gui 2
|
|
targets React Native 0.81, React 19, and TypeScript 5 and above with New
|
|
Architecture support. This enables significant new style features, improved
|
|
type inference, and simplified internals.
|
|
- Default flex and position styles align with the latest React Native versions,
|
|
(you can change settings to keep the legacy behavior).
|
|
- Button and ListItem lose direct text style props for better performance and
|
|
consistency.
|
|
- useTheme no longer takes props; use the Theme component instead.
|
|
- Removed web-only `onHoverIn` and `onHoverOut` in favor of standard web events
|
|
(`onMouseEnter` or `onPointerEnter`).
|
|
- Added comprehensive web event handler support including keyboard, pointer,
|
|
drag and drop, clipboard, and scroll events.
|
|
- Moved from ThemeableStack to View for most base components in UI.
|
|
- Removed deprecated `Stack` for the identical `View`.
|
|
- Renamed the `animation` prop to `transition` for clarity and consistency.
|
|
- Removed `<Theme inverse />` and `themeInverse` prop - see
|
|
[inverse themes guide](/docs/guides/theme-builder#inverse-themes).
|
|
- Removed the `maxDarkLightNesting` and `cssStyleSeparator` settings.
|
|
- Removed `space` and `spaceDirection` props - use `gap` instead.
|
|
- Tabs `activationMode` now defaults to `'manual'` instead of `'automatic'`.
|
|
This means focusing a tab no longer changes the active tab - you must click or
|
|
press Enter/Space. This matches web standards.
|
|
- Group component simplified: `Group.Item` is now required (no more auto-cloning
|
|
direct children). Removed props: `space`, `separator`, `scrollable`,
|
|
`showScrollIndicator`, `disablePassBorderRadius`, `forceUseItem`. Children now
|
|
control their own sizing - apply size/responsive props directly to child
|
|
components. Add `<Separator />` manually between items when needed.
|
|
- Moved `<Spacer />` from core to `@hanzogui/spacer`.
|
|
- Moved all settings on `createGui` to the `settings` object.
|
|
- Native portals no longer auto-import React internals hack. If you want native
|
|
portals for better context preservation, add
|
|
`import '@hanzogui/native/setup-teleport'` at app startup. See
|
|
[Portal docs](/docs/components/portal).
|
|
- LinearGradient on native now requires setup import. Add
|
|
`import '@hanzogui/native/setup-expo-linear-gradient'` at app startup. See
|
|
[LinearGradient docs](/docs/components/linear-gradient).
|
|
- Removed React Native accessibility props in favor of web-standard props:
|
|
- `accessibilityLabel` → `aria-label`
|
|
- `accessibilityRole` → `role`
|
|
- `accessibilityHint` → `aria-describedby`
|
|
- `accessibilityState` → `aria-disabled`, `aria-selected`, `aria-checked`,
|
|
`aria-busy`, `aria-expanded`
|
|
- `accessibilityValue` → `aria-valuemin`, `aria-valuemax`, `aria-valuenow`,
|
|
`aria-valuetext`
|
|
- `accessibilityElementsHidden` → `aria-hidden`
|
|
- `accessibilityViewIsModal` → `aria-modal`
|
|
- `accessibilityLiveRegion` → `aria-live`
|
|
- `accessible` → `tabIndex={0}`
|
|
- `focusable` → `tabIndex`
|
|
- `nativeID` → `id`
|
|
|
|
### Goals
|
|
|
|
Our main goal with version two is **stability**. Gui started as a side
|
|
project with incredible scope and maintained an ambitious stance towards landing
|
|
large features and internal improvements.
|
|
|
|
Speaking for myself now: I personally pushed releases too fast, and as a result
|
|
burned too many of our users with regressions. We generally fast-followed with
|
|
fixes, but that isn't good enough.
|
|
|
|
I'd like to apologize for that, sincerely. We had a v2 nearly ready over a year
|
|
ago, but it felt right to push back the release until we felt confident we'd
|
|
fixed nearly every major issue, and overhauled our testing setup.
|
|
|
|
React Native is difficult to test, so it took us a while to build it out, but
|
|
I'm incredibly happy with where we're at now. On every commit we're running
|
|
integration tests on iOS and Android across every complex component, alongside a
|
|
few thousand web and core tests.
|
|
|
|
#### Testing
|
|
|
|
The testing infrastructure has been completely rebuilt since v1. At the v1.0
|
|
release we had 13 test files and a single CI workflow. Today we have 127 test
|
|
files across 5 testing frameworks with dedicated native testing infrastructure.
|
|
|
|
**Frameworks added:**
|
|
|
|
- **Playwright** for E2E and integration tests
|
|
- **Vitest** for unit and integration tests
|
|
- **Jest + Detox** for iOS and Android native E2E testing
|
|
- **Maestro** for iOS flow-based testing
|
|
|
|
**Multi-driver testing:** Every Playwright UI test runs four times, once for
|
|
each animation driver. This catches driver-specific regressions that would
|
|
otherwise slip through.
|
|
|
|
### What's next
|
|
|
|
Gui is quite mature in terms of features, foundation, and performance. AI
|
|
Agents generate its code exceptionally well because it's been in wide use and
|
|
well documented for years. For this reason, we are avoiding large syntax or
|
|
theme changes, for now.
|
|
|
|
We're going to deprecate a variety of things in 2.1 that will be planned for
|
|
3.0, and will follow with 3.0 a lot quicker than this major took.
|
|
|
|
There's still some work to do in terms of simplifying internals, we'd like to
|
|
move both our built-in styles and standardized sizing to be done in a more clear
|
|
way where it's easy to unplug either. Other broad goals include better alignment
|
|
to the web, simpler onboarding, more components, better components, and more
|
|
native component integrations.
|
|
|
|
### Thanks
|
|
|
|
A huge thanks is owed to our amazing team, which has persisted through this
|
|
giant release and throughout the last two years fixing issues.
|
|
|
|
Special thanks to [Quan Nguyen](https://github.com/anhquan291) for extensive
|
|
work on documentation, Radix v3 color updates, and theme improvements. And to
|
|
[Dave Mkpa-Eke](https://github.com/DaveyEke)
|
|
([@1804davey](https://x.com/1804davey)) for numerous bug fixes across Progress,
|
|
Input, ContextMenu, and other components, as well as the new Select.Indicator
|
|
feature and blog improvements.
|