apps/docs/content/docs/en/native/releases/rc-3.mdx
RC 3 delivers three new components—TagGroup for selectable tag management, Menu for popover/bottom-sheet-based dropdown menus, and InputGroup for decorated text inputs with auto-measuring prefix/suffix slots. This release also brings Android hardware back button support for all bottom-sheet-based overlays, Expo 55 compatibility with a critical combineStyles fix that preserves Reanimated animated style bindings, and several dependency upgrades.
Update to the latest version:
<Tabs items={["npm", "pnpm", "yarn", "bun"]}> <Tab value="npm">
npm i heroui-native
This release introduces 3 new components:
The TagGroup component provides a compound component pattern for rendering selectable tag groups with optional removal support. It supports single and multiple selection modes, controlled and uncontrolled APIs, two visual variants (default and surface), three sizes, disabled states, and full form field integration with Label, Description, and FieldError.
<NativeVideoPlayerView target="component" slug="tag-group" srcLight="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/tag-group-docs-light.mp4" srcDark="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/tag-group-docs-dark.mp4" />
Features:
TagGroup.List, TagGroup.Item, TagGroup.ItemLabel, TagGroup.ItemRemoveButtondefault and surfacesm, md, lgdisabledKeys supportonRemove callback and TagGroup.ItemRemoveButtonrenderEmptyState on TagGroup.ListisInvalid, and isRequireduseTagGroup and useTagGroupItem hooks for advanced use casesUsage:
import { TagGroup } from "heroui-native";
export function BasicTagGroup() {
return (
<TagGroup>
<TagGroup.List>
<TagGroup.Item id="react">
<TagGroup.ItemLabel>React</TagGroup.ItemLabel>
</TagGroup.Item>
<TagGroup.Item id="vue">
<TagGroup.ItemLabel>Vue</TagGroup.ItemLabel>
</TagGroup.Item>
<TagGroup.Item id="svelte">
<TagGroup.ItemLabel>Svelte</TagGroup.ItemLabel>
</TagGroup.Item>
</TagGroup.List>
</TagGroup>
);
}
export function RemovableTagGroup() {
const [items, setItems] = useState(["React", "Vue", "Svelte"]);
return (
<TagGroup onRemove={(keys) => setItems((prev) => prev.filter((i) => !keys.has(i)))}>
<TagGroup.List>
{items.map((item) => (
<TagGroup.Item key={item} id={item}>
<TagGroup.ItemLabel>{item}</TagGroup.ItemLabel>
<TagGroup.ItemRemoveButton />
</TagGroup.Item>
))}
</TagGroup.List>
</TagGroup>
);
}
For complete documentation and examples, see the TagGroup component page.
Related PR: #309
The Menu component provides a dropdown menu system built on a compound component pattern, supporting both popover and bottom-sheet presentation modes. It includes full Reanimated-based press animations, single and multiple selection modes, item variants (default and danger), indicator styles, and configurable placement.
<NativeVideoPlayerView target="component" slug="menu" srcLight="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/menu-docs-light.mp4" srcDark="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/menu-docs-dark.mp4" />
Features:
Menu.Trigger, Menu.Portal, Menu.Overlay, Menu.Content, Menu.Label, Menu.Group, Menu.Item, Menu.ItemTitle, Menu.ItemDescription, Menu.ItemIndicatorpopover and bottom-sheet with configurable placement (top, bottom, left, right)Menu.Group with selectedKeys/onSelectionChangeanimation propdefault and dangercheckmark, dot, and custom contentMenu.Label for section headingsshouldCloseOnSelect control per groupUsage:
import { Menu } from "heroui-native";
export function BasicMenu() {
return (
<Menu>
<Menu.Trigger>
<Button>Open Menu</Button>
</Menu.Trigger>
<Menu.Portal>
<Menu.Overlay />
<Menu.Content>
<Menu.Item>
<Menu.ItemTitle>Edit</Menu.ItemTitle>
</Menu.Item>
<Menu.Item>
<Menu.ItemTitle>Duplicate</Menu.ItemTitle>
</Menu.Item>
<Menu.Item variant="danger">
<Menu.ItemTitle>Delete</Menu.ItemTitle>
</Menu.Item>
</Menu.Content>
</Menu.Portal>
</Menu>
);
}
export function MenuWithSections() {
return (
<Menu>
<Menu.Trigger>
<Button>Actions</Button>
</Menu.Trigger>
<Menu.Portal>
<Menu.Overlay />
<Menu.Content>
<Menu.Group selectionMode="single" selectedKeys={selected} onSelectionChange={setSelected}>
<Menu.Label>View</Menu.Label>
<Menu.Item id="list">
<Menu.ItemTitle>List View</Menu.ItemTitle>
<Menu.ItemIndicator />
</Menu.Item>
<Menu.Item id="grid">
<Menu.ItemTitle>Grid View</Menu.ItemTitle>
<Menu.ItemIndicator />
</Menu.Item>
</Menu.Group>
</Menu.Content>
</Menu.Portal>
</Menu>
);
}
For complete documentation and examples, see the Menu component page.
Related PR: #312
The InputGroup component provides a decorated text input with absolutely-positioned Prefix and Suffix sub-components that automatically measure their widths via onLayout and apply matching padding to the Input. It features a convenient isDecorative prop that handles accessibility and pointer-event boilerplate for decorative addons in a single boolean, and a root isDisabled prop that cascades disabled state to all children via context.
<NativeVideoPlayerView target="component" slug="input-group" srcLight="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/input-group-docs-light.mp4" srcDark="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/native/components/videos/input-group-docs-dark.mp4" />
Features:
InputGroup.Prefix, InputGroup.Suffix, InputGroup.InputonLayout and automatically applied as paddingLeft/paddingRight on the InputisDecorative prop on Prefix/Suffix handles pointerEvents="none", accessibilityElementsHidden, and importantForAccessibility in a single booleanisDisabled cascades to all children via context (Prefix/Suffix opacity + pointer-events, Input editability)InputGroup.Input is a direct pass-through — consumers manage value/onChangeText directly on the InputUsage:
import { InputGroup } from "heroui-native";
export function SearchInput() {
return (
<InputGroup>
<InputGroup.Prefix isDecorative>
<SearchIcon />
</InputGroup.Prefix>
<InputGroup.Input placeholder="Search..." />
<InputGroup.Suffix isDecorative>
<ChevronIcon />
</InputGroup.Suffix>
</InputGroup>
);
}
export function DisabledInput() {
return (
<InputGroup isDisabled>
<InputGroup.Prefix isDecorative>
<LockIcon />
</InputGroup.Prefix>
<InputGroup.Input placeholder="Disabled input" />
</InputGroup>
);
}
For complete documentation and examples, see the InputGroup component page.
Related PR: #313
The Bottom Sheet shared container now handles the Android hardware back button, dismissing any open bottom sheet when pressed. The BackHandler listener is only active while the sheet is open, preventing closed instances from consuming the event. This fix applies globally to all bottom-sheet-based components.
Supported components:
The fix uses React Native's BackHandler API which is a no-op on iOS, so no platform-specific handling is needed.
Related PR: #308
combineStyles FixThe Slot primitive's combineStyles function now returns style arrays instead of using StyleSheet.flatten, which was destroying Reanimated SharedValue and useAnimatedStyle bindings by deep-copying style objects into plain objects.
Improvements:
combineStyles preserves Reanimated animated style bindings by returning arraysRelated PR: #314
Dependency versions have been updated for Expo SDK 55 compatibility:
uniwind: 1.2.7 → 1.3.2@gorhom/bottom-sheet: ^5 → ^5.2.8The combineStyles fix described above is the primary code change enabling Expo 55 support, as the previous StyleSheet.flatten approach broke Reanimated style bindings in the new SDK.
Related PR: #314
This release includes fixes for the following issues:
Issue #272: Resolved FullWindowOverlay interfering with the React Native element inspector.
Issue #280: Fixed Avatar component and other Reanimated-dependent components breaking under Expo 55. The combineStyles function was destroying Reanimated animated style bindings via StyleSheet.flatten; it now returns style arrays to preserve SharedValue and useAnimatedStyle bindings.
Related PRs:
The following documentation pages have been updated to reflect the changes in this release:
Thanks to everyone who contributed to this release!