Adds Table, Carousel, MorphButton, and PhoneNumberField, plus a theme-aware background layer for carousel navigation buttons.
The tenth beta of HeroUI Native Pro ships four new surfaces — a compound Table for selectable, sortable tabular data, a Carousel snap pager with navigation, interpolating dots, and thumbnails, a MorphButton that springs between collapsed and expanded content, and a PhoneNumberField with per-country as-you-type formatting. Carousel Previous/Next buttons also pick up a theme-aware background layer so glass nav chevrons frost correctly.
Follow the installation guide to authenticate the private registry with your HEROUI_PERSONAL_TOKEN, install heroui-native-pro, and wire up HeroUINativeProvider.
This release introduces 4 new components across data display, buttons, and forms:
useCarousel() for custom scroll-driven indicators. (Documentation)A compound data table for lists that need columns, selection, and sort without a web-style grid. Compose a header of columns and a body of rows, wrap wide content in a horizontal scroll container, and keep summaries or load-more actions in a footer outside that scroll. The table never reorders data itself — mark columns with allowsSorting, sort from sortDescriptor, and pass the result back in.
Features:
Table.ScrollContainer, Table.Content, Table.Header, Table.Column, Table.Body, Table.Row, Table.Cell, Table.SelectAllCell, Table.SelectionCell, Table.Footer, and Table.Backgroundnone / single / multiple selection, with row press toggling selection when the mode is not "none"sortDescriptor / onSortChange; the table never mutates your items arraywidth, or flex + minWidth) seeded before first paint so header and body cells align without a layout flashitems render-function body, renderEmptyState, and an opt-in virtualized FlatList body for large collectionsprimary / secondary variants and a theme-aware background layer on the shell (glass renders a blur)Usage:
import { Chip } from "heroui-native";
import { Table } from "heroui-native-pro";
const MEMBERS = [
{
id: "1",
name: "Ava Thompson",
role: "Design",
status: "Active",
statusColor: "success" as const,
},
{
id: "2",
name: "Liam Nguyen",
role: "Engineering",
status: "Paused",
statusColor: "warning" as const,
},
{
id: "3",
name: "Maya Patel",
role: "Product",
status: "Active",
statusColor: "success" as const,
},
];
export function Example() {
return (
<Table>
<Table.ScrollContainer>
<Table.Content>
<Table.Header>
<Table.Column flex={1.3}>Name</Table.Column>
<Table.Column>Role</Table.Column>
<Table.Column width={110}>Status</Table.Column>
</Table.Header>
<Table.Body>
{MEMBERS.map((member) => (
<Table.Row key={member.id} id={member.id}>
<Table.Cell>{member.name}</Table.Cell>
<Table.Cell textProps={{ numberOfLines: 1 }}>{member.role}</Table.Cell>
<Table.Cell>
<Chip color={member.statusColor} size="sm" variant="soft">
{member.status}
</Chip>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Content>
</Table.ScrollContainer>
</Table>
);
}For complete documentation and examples, see the Table component page.
A horizontal snap pager for galleries, product images, and similar slide layouts. The root owns the snap engine — viewport measurement, slide width, snap offsets, and autoplay — and exposes useCarousel() for custom scroll-driven indicators. Navigation presses commit immediately; a swipe commits at the halfway point between two snap points.
Features:
Carousel.Content, Carousel.Item, Carousel.Previous / Carousel.Next, Carousel.Dots, Carousel.Thumbnails / Carousel.Thumbnail, plus useCarousel()itemsPerView (fractional values peek the next slide), gap, engine-owned sidePadding, align, and type (in-place / modal / miniatures)stopAutoPlayOnInteraction stops permanently on the first gesture by defaultprogress on the UI thread; renderDot replaces the default pillsCarousel.NavButtonBackground on Previous/Next — undefined renders the theme default, a custom node replaces it, null removes itUsage:
import { Carousel } from "heroui-native-pro";
import { Image } from "react-native";
const SLIDES = [
{ id: "1", uri: "https://example.com/photo-1.jpg" },
{ id: "2", uri: "https://example.com/photo-2.jpg" },
{ id: "3", uri: "https://example.com/photo-3.jpg" },
];
export function Example() {
return (
<Carousel>
<Carousel.Content>
{SLIDES.map((slide) => (
<Carousel.Item key={slide.id} className="aspect-4/3 rounded-3xl overflow-hidden">
<Image source={{ uri: slide.uri }} className="absolute inset-0 size-full" />
</Carousel.Item>
))}
</Carousel.Content>
<Carousel.Previous />
<Carousel.Next />
<Carousel.Dots />
</Carousel>
);
}For complete documentation and examples, see the Carousel component page.
A pressable surface that morphs between auto-measured collapsed and expanded content. The root's layout footprint always equals the collapsed size, so the expanding panel overflows without shifting siblings. Both content parts are measured up front — expanded content stays mounted while hidden — so the first open already knows its target size.
Features:
MorphButton.CollapsedContent and MorphButton.ExpandedContentdirections (top, top-end, end, bottom-end, bottom, bottom-start, start, top-start); start / end mirror in RTLprimary / secondary variants — inverted floating surface vs. a card-friendly fillisOpen / onOpenChange) and uncontrolled (defaultOpen) open stateanimation.morphSpringConfig, or "disable-all" to snap every transitionUsage:
import { MorphButton } from "heroui-native-pro";
import { Text, View } from "react-native";
export function Example() {
return (
<View className="absolute bottom-6 inset-x-0 items-center">
<MorphButton direction="top">
<MorphButton.CollapsedContent>
<Text className="text-sm font-medium text-background">2 products in bag</Text>
</MorphButton.CollapsedContent>
<MorphButton.ExpandedContent className="w-72">
<Text className="text-base font-semibold text-background">Order summary</Text>
</MorphButton.ExpandedContent>
</MorphButton>
</View>
);
}For complete documentation and examples, see the MorphButton component page.
An international phone number field with per-country as-you-type formatting, a searchable country picker, smart paste, and E.164 output. Formatting uses #-template masks generated from libphonenumber-js metadata, so grouping stays stable as the user types — digits never rearrange mid-word. Validation, region detection, and length limits use libphonenumber-js when the optional peer is installed.
Features:
InputGroup, Prefix, Input, Select, Trigger, Portal, Overlay, Content, ContentBackground, ContentHandle, SearchInput, CountryList, CountryItem, Suffix+ and keep the digits; choosing a country from the picker clears themonValueChange reports digits, formatted value, E.164, country, and isValid / isComplete flagsUsage:
import { Description, Label } from "heroui-native";
import { PhoneNumberField } from "heroui-native-pro";
export function Example() {
return (
<PhoneNumberField>
<Label>Phone number</Label>
<PhoneNumberField.InputGroup>
<PhoneNumberField.Prefix>
<PhoneNumberField.Select>
<PhoneNumberField.Trigger />
<PhoneNumberField.Portal>
<PhoneNumberField.Overlay />
<PhoneNumberField.Content>
<PhoneNumberField.ContentHandle />
<PhoneNumberField.SearchInput />
<PhoneNumberField.CountryList />
</PhoneNumberField.Content>
</PhoneNumberField.Portal>
</PhoneNumberField.Select>
</PhoneNumberField.Prefix>
<PhoneNumberField.Input />
</PhoneNumberField.InputGroup>
<Description>We'll send a verification code to this number</Description>
</PhoneNumberField>
);
}For complete documentation and examples, see the PhoneNumberField component page.
Declared as an optional peer dependency and loaded through an optional import helper. Required for metadata-driven validation, E.164 output, region detection from a pasted number, and per-prefix length limits. Without it, isValid degrades to a completeness check and e164 is the dial code plus digits; formatting is unchanged because it comes from the built-in mask table.
npx expo install libphonenumber-jsRegenerate the fallback mask table with node scripts/generate-phone-number-masks.js after upgrading libphonenumber-js.
The following documentation has been added or updated to reflect the changes in this release:
useCarousel(), and nav button backgroundslibphonenumber-js peer