Opinionated React Native and React Native Web UI kit built on
@ankhorage/surface.
ZORA sits above Surface. Surface provides the foundation primitives, theme system, and low-level controls; ZORA adds product-facing components, app layouts, and ready-made patterns with stronger defaults.
bun add @ankhorage/zoraPeer dependencies:
react >=18.2.0react-native >=0.72.0@expo/vector-icons >=14.0.0when using icon specsexpo-font >=14.0.4when using runtime font registration
Wrap your app in ZoraProvider, then import components from
@ankhorage/zora.
import React from 'react';
import {
AppShell,
Button,
Card,
Heading,
Page,
PageHeader,
Text,
Toolbar,
ToolbarAction,
ZoraProvider,
} from '@ankhorage/zora';
export function App() {
return (
<ZoraProvider>
<AppShell
header={
<Toolbar>
<ToolbarAction icon={{ name: 'menu-outline' }} label="Menu" />
</Toolbar>
}
>
<Page header={<PageHeader title="Dashboard" description="Ready to build." />}>
<Card
actions={<Button>Continue</Button>}
description="ZORA provides composed UI surfaces for apps."
title="Welcome"
>
<Heading level={3}>Next steps</Heading>
<Text tone="muted">Structured text comes from ZORA too.</Text>
</Card>
</Page>
</AppShell>
</ZoraProvider>
);
}ZORA supports nested theme scopes. A component may set mode and, later,
themeId; everything inside inherits the nearest scope.
import React from 'react';
import { Button, Heading, Panel, Text, ZoraProvider, type ZoraTheme } from '@ankhorage/zora';
export function App({ appTheme }: { appTheme: ZoraTheme }) {
return (
<ZoraProvider theme={appTheme} initialMode="light">
<Panel mode="dark">
<Heading>Studio panel</Heading>
<Text>Text inherits dark mode.</Text>
<Button>Also scoped.</Button>
</Panel>
</ZoraProvider>
);
}ZORA themes use a single seed primaryColor. ZORA derives mode-specific primary
colors for light and dark mode internally.
<ZoraProvider
theme={{
id: 'studio',
primaryColor: '#0f766e',
harmony: 'analogous',
colorTone: 'jewel',
}}
>
<App />
</ZoraProvider>
colorTonevs componenttone—colorToneis a theme-seed field that selects the color-world / palette tone for the whole theme (e.g.'jewel','pastel'). Componenttoneprops (e.g.<Text tone="muted" />,<Button tone="primary" />) express semantic color intent inside that theme and are independent ofcolorTone.
mode and themeId are available on public ZORA components through ZoraBaseProps.
Use component props for local component/subtree overrides.
Use ZoraThemeScope when the scope is conceptual and does not belong to one specific component:
import React from 'react';
import { SidebarLayout, Text, ZoraProvider, ZoraThemeScope, type ZoraTheme } from '@ankhorage/zora';
export function App({ appTheme }: { appTheme: ZoraTheme }) {
return (
<ZoraProvider theme={appTheme} initialMode="light">
<ZoraThemeScope mode="dark">
<SidebarLayout sidebar={<Text>Sidebar</Text>}>
<Text>Everything inside uses dark mode.</Text>
</SidebarLayout>
</ZoraThemeScope>
</ZoraProvider>
);
}themeId currently accepts the inherited theme id. Full theme registries arrive in a later phase.
ZORA re-exports selected Surface foundation primitives for app-facing layout code:
import { Box, Container, Grid, Heading, Stack, Text } from '@ankhorage/zora';Use ZORA Text and Heading for typography. Use Box, Stack, Grid, and
Container for layout. Surface remains the lower-level render foundation and
should not be required in normal app-facing UI code.
These unions appear across the catalogue:
ZoraTonecomes from SurfaceButtonProps['tone'].ZoraEmphasiscomes from SurfaceButtonProps['variant'].ZoraBadgeEmphasiscomes from SurfaceBadgeProps['variant'].ZoraControlSizecomes from SurfaceButtonProps['size'].ZoraCardTone = 'default' | 'subtle' | 'outline'.ZoraContentWidth = 'narrow' | 'default' | 'wide'.
Width presets:
- Dialog widths:
narrow=420,default=520,wide=560. - Page widths:
narrow=760,default=1040,wide=1280.
Structured titles with semantic levels, visual sizes, semantic tones, and
responsive props. Use Heading for titles and Text for body copy.
<Heading level={1} size={{ base: 'h2', md: 'h1' }}>
Build faster with ZORA
</Heading>
<Heading level={2} tone="primary">
Create consistent screens
</Heading>level expresses document hierarchy. size controls visual scale and can be
responsive for mobile and web layouts.
Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Primary content. |
text |
string |
- | Manifest-friendly content prop. |
i18nKey |
string |
- | Runtime-resolved fallback key when no content prop is provided. |
level |
HeadingLevel |
2 |
Semantic heading level from 1 through 6. |
size |
Responsive<HeadingSize> |
level size | Visual scale: display, h1 through h6. |
tone |
Responsive<HeadingTone> |
'default' |
Semantic text color. |
align |
Responsive<HeadingAlign> |
- | Text alignment. |
weight |
Responsive<HeadingWeight> |
recipe | Optional structured weight override. |
italic |
boolean |
false |
Italic style. |
numberOfLines |
number |
- | Native/web truncation line count. |
ellipsizeMode |
'head' | 'middle' | 'tail' | 'clip' |
- | Truncation behavior. |
selectable |
boolean |
- | Allows text selection where supported. |
testID |
string |
- | Test id. |
No inherited props. HeadingProps is declared directly by ZORA to keep heading
usage structured and template-safe.
Structured body text with ZORA typography variants, semantic tones, and responsive props.
<Text variant="lead" tone="muted">
Build product screens with structured, theme-aware copy.
</Text>
<Text variant={{ base: 'bodySmall', md: 'body' }} align={{ base: 'center', md: 'left' }}>
Responsive text without raw styles.
</Text>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Primary content. |
text |
string |
- | Manifest-friendly content prop. |
i18nKey |
string |
- | Runtime-resolved fallback key when no content prop is provided. |
variant |
Responsive<TextVariant> |
'body' |
Typography recipe. |
tone |
Responsive<TextTone> |
'default' |
Semantic text color. |
align |
Responsive<TextAlign> |
- | Text alignment. |
weight |
Responsive<TextWeight> |
recipe | Optional structured weight override. |
italic |
boolean |
false |
Italic style. |
numberOfLines |
number |
- | Native/web truncation line count. |
ellipsizeMode |
'head' | 'middle' | 'tail' | 'clip' |
- | Truncation behavior. |
selectable |
boolean |
- | Allows text selection where supported. |
testID |
string |
- | Test id. |
No inherited props. TextProps is declared directly by ZORA to keep text
structured and template-safe.
Action button with ZORA defaults for tone, emphasis, size, and icons.
<Button leadingIcon={{ name: 'checkmark-circle-outline' }}>Save</Button>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Button label or content. |
tone |
ZoraTone |
'primary' |
Passed to Surface as tone. |
emphasis |
ZoraEmphasis |
'solid' |
Passed to Surface as variant. |
size |
ZoraControlSize |
'l' |
Passed to Surface as size. |
leadingIcon |
ButtonIconSpec |
- | Surface icon spec rendered before content. |
trailingIcon |
ButtonIconSpec |
- | Surface icon spec rendered after content. |
Inherited props:
Inherits all Surface ButtonProps except children, size, tone, and
variant. This includes Surface button behavior such as loading,
fullWidth, pressability props, disabled state, accessibility props allowed by
Surface, and testID.
Compact icon-only button for toolbars, rows, and actions.
<IconButton icon={{ name: 'trash-outline' }} label="Delete" tone="danger" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
icon |
ButtonIconSpec |
- | Required icon to render. |
label |
string |
- | Required for accessibilityLabel. |
tone |
ZoraTone |
'neutral' |
Button tone. |
emphasis |
ZoraEmphasis |
'ghost' |
Button emphasis. |
size |
ZoraControlSize |
'm' |
Button size. |
Inherited props:
Inherits behavior from Surface IconButton including disabled, loading,
onPress, and testID.
Small status label with ZORA tone, emphasis, and size defaults.
<Badge tone="success">Active</Badge>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Rendered as Surface badge content. |
tone |
ZoraTone |
'primary' |
Passed to Surface as tone. |
emphasis |
ZoraBadgeEmphasis |
'soft' |
Passed to Surface as variant. |
size |
ZoraControlSize |
'm' |
Passed to Surface as size. |
Inherited props:
Inherits all Surface BadgeProps except content, size, tone, and
variant. The remaining inherited prop is testID.
Composed content surface with optional header, actions, footer, and ZORA card tones.
<Card actions={<Button>Open</Button>} description="A reusable product surface." title="Project" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Main card body. |
title |
React.ReactNode |
- | Header title. |
description |
React.ReactNode |
- | Header description. |
eyebrow |
React.ReactNode |
- | Small muted text above the title. |
actions |
React.ReactNode |
- | Header action area. |
footer |
React.ReactNode |
- | Footer area below body content. |
tone |
ZoraCardTone |
'default' |
Maps to Surface variants: default -> raised, subtle -> subtle, outline -> outline. |
compact |
boolean |
false |
Uses tighter padding and heading scale. |
Inherited props:
Inherits all Surface CardProps except children, p, radius, variant, and
style. ZORA owns spacing, radius, and variant selection for this wrapper.
Text input wrapper with ZORA sizing and optional Surface icon specs.
<Input
autoCapitalize="none"
keyboardType="email-address"
leadingIcon={{ name: 'mail-outline' }}
placeholder="you@example.com"
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
size |
ZoraControlSize |
'l' |
Passed to Surface as size. |
leadingIcon |
ButtonIconSpec |
- | Rendered as Surface leadingAccessory. |
trailingIcon |
ButtonIconSpec |
- | Rendered as Surface trailingAccessory. |
Inherited props:
Inherits all Surface TextInputProps except leadingAccessory, size, and
trailingAccessory. Surface TextInputProps also inherit React Native
TextInputProps except defaultValue, editable, onChangeText,
placeholderTextColor, style, testID, and value; Surface re-exposes
value, defaultValue, onChangeText, placeholder, disabled, readOnly,
invalid, style, and testID.
Single-selection control built on top of Surface Radio, designed for use inside FormField.
<FormField label="Navigator type">
<RadioGroup
value="tabs"
onValueChange={(value) => console.log(value)}
options={[
{ value: 'tabs', label: 'Tabs' },
{ value: 'drawer', label: 'Drawer' },
]}
/>
</FormField>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
value |
string |
- | Currently selected value. |
onValueChange |
(value: string) => void |
- | Called when selection changes. |
options |
RadioGroupOption[] |
- | List of selectable options. |
orientation |
'horizontal' | 'vertical' |
'vertical' |
Layout direction. |
gap |
'xs' | 's' | 'm' | 'l' |
's' |
Spacing between items. |
Option shape:
type RadioGroupOption = {
value: string;
label: React.ReactNode;
description?: React.ReactNode;
disabled?: boolean;
};Inherited props:
Passes tone, size, invalid, readOnly, disabled, and testID
to underlying Surface Radio components.
Multi-selection control built on top of Surface Checkbox, for selecting multiple values.
<FormField label="Features">
<CheckboxGroup
value={['a']}
onValueChange={(value) => console.log(value)}
options={[
{ value: 'a', label: 'Feature A' },
{ value: 'b', label: 'Feature B' },
]}
/>
</FormField>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
value |
string[] |
- | Array of selected values. |
onValueChange |
(value: string[]) => void |
- | Called when selection changes. |
options |
CheckboxGroupOption[] |
- | List of selectable options. |
orientation |
'horizontal' | 'vertical' |
'vertical' |
Layout direction. |
gap |
'xs' | 's' | 'm' | 'l' |
's' |
Spacing between items. |
Option shape:
type CheckboxGroupOption = {
value: string;
label: React.ReactNode;
description?: React.ReactNode;
disabled?: boolean;
};Inherited props:
Passes tone, size, invalid, readOnly, disabled, and testID
to underlying Surface Checkbox components.
Multiline text input wrapper with ZORA sizing and optional Surface icon specs.
<Textarea leadingIcon={{ name: 'document-text-outline' }} rows={5} />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
size |
ZoraControlSize |
'l' |
Passed to Surface as size. |
leadingIcon |
ButtonIconSpec |
- | Rendered as Surface leadingAccessory. |
trailingIcon |
ButtonIconSpec |
- | Rendered as Surface trailingAccessory. |
Inherited props:
Inherits all Surface TextareaProps except leadingAccessory, size, and
trailingAccessory. Surface TextareaProps extend Surface TextInputProps
except multiline, so React Native text input props are available through
Surface with the same Surface exclusions and re-exposed values listed for
Input.
Generic controlled tabs for navigation and filtering.
<Tabs
items={[
{ value: 'all', label: 'All' },
{ value: 'active', label: 'Active' },
]}
onValueChange={setValue}
value={value}
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
value |
string |
- | Active tab value. |
items |
TabItem[] |
- | Array of tab objects. |
onValueChange |
(value: string) => void |
- | Change handler. |
variant |
'underline' | 'pill' | 'segmented' |
'underline' |
Visual style. |
size |
ZoraControlSize |
'm' |
Control size. |
Horizontal shell for actions and tools.
<Toolbar>
<ToolbarAction icon={{ name: 'add-outline' }} label="Add" />
<ToolbarAction icon={{ name: 'search-outline' }} label="Search" />
</Toolbar>Props
Toolbar props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Toolbar content. |
position |
'top' | 'bottom' | 'inline' |
'inline' |
Layout position. |
floating |
boolean |
false |
Whether the toolbar floats with a shadow. |
compact |
boolean |
true |
Tighter padding. |
ToolbarAction props:
| Prop | Type | Default | Notes |
|---|---|---|---|
icon |
ButtonIconSpec |
- | Required icon. |
label |
string |
- | Accessibility label. |
active |
boolean |
false |
Highlighted state. |
onPress |
() => void |
- | Click handler. |
Standard dropdown selector wrapping @react-native-picker/picker.
<Select
onValueChange={setValue}
options={[
{ value: '1', label: 'Option 1' },
{ value: '2', label: 'Option 2' },
]}
value={value}
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
value |
string |
- | Selected value. |
options |
SelectOption[] |
- | Array of option objects. |
onValueChange |
(value: string) => void |
- | Change handler. |
invalid |
boolean |
false |
Error state styling. |
disabled |
boolean |
false |
Interaction state. |
Centered overlay shell with optional header, body, footer, and width preset.
<Modal footer={<Button>Done</Button>} onDismiss={close} title="Details" visible={visible} />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Modal body. |
title |
React.ReactNode |
- | Header title. |
description |
React.ReactNode |
- | Header description. |
footer |
React.ReactNode |
- | Footer area. |
width |
ZoraContentWidth |
'default' |
Resolves to 420, 520, or 560 pixels. |
Inherited props:
Picks these Surface ModalProps: closeOnBackdrop, onDismiss, testID, and
visible.
Side overlay shell with optional header, body, and footer.
<Drawer onDismiss={close} title="Filters" visible={visible}>
{content}
</Drawer>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Drawer body. |
title |
React.ReactNode |
- | Header title. |
description |
React.ReactNode |
- | Header description. |
footer |
React.ReactNode |
- | Footer area. |
Inherited props:
Picks these Surface DrawerProps: closeOnBackdrop, onDismiss, position,
testID, and visible.
Theme-aware application root shell providing the structural frame for an app.
It defines the top-level layout slots (header, body, footer, overlay)
and ensures a full-height, flexible container.
Use it as the outer layout inside ZoraProvider. Combine it with layout
primitives like SidebarLayout or Page to structure inner content.
<AppShell header={<Toolbar position="inline">{actions}</Toolbar>} footer={<BottomBar />}>
<Page header={<PageHeader title="Dashboard" />}>{content}</Page>
</AppShell>Example with overlay (e.g. mobile panel or drawer):
<AppShell footer={<BottomBar />} overlay={isOpen ? <MyDrawer onClose={close} /> : null}>
{content}
</AppShell>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Main application content. |
header |
React.ReactNode |
- | Optional top section (e.g. toolbar or navigation). |
footer |
React.ReactNode |
- | Optional bottom section (e.g. tab bar or actions). |
overlay |
React.ReactNode |
- | Optional overlay layer rendered above content (e.g. drawer, modal, floating panels). |
style |
StyleProp<ViewStyle> |
- | Style applied to the root container. |
bodyStyle |
StyleProp<ViewStyle> |
- | Style applied to the main content container. |
testID |
string |
- | Forwarded to the root Surface container. |
Inherited props:
No inherited props. AppShellProps is declared directly by ZORA.
-
AppShellis a structural primitive, not a page layout. -
It does not manage sidebars or content splits — use
SidebarLayoutfor that. -
It does not provide theming — wrap with
ZoraProvider. -
overlayis rendered using absolute positioning and should be used for drawers, mobile panels, or floating UI. -
All inner content must support flexible layouts (
flex: 1,minHeight: 0) to behave correctly inside the shell.
Constrained page container with optional header and footer slots.
<Page header={<PageHeader title="Projects" />} width="wide">
{content}
</Page>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Page body. |
header |
React.ReactNode |
- | Rendered above body content. |
footer |
React.ReactNode |
- | Rendered below body content. |
width |
ZoraContentWidth |
'default' |
Resolves to 760, 1040, or 1280 pixels. |
testID |
string |
- | Forwarded to the root Surface container. |
Inherited props:
No inherited props. PageProps is declared directly by ZORA.
Top-level page heading with optional eyebrow, metadata, and actions.
<PageHeader actions={<Button>New</Button>} title="Projects" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Required page title. |
description |
React.ReactNode |
- | Supporting copy below title. |
eyebrow |
React.ReactNode |
- | Small muted text above title. |
actions |
React.ReactNode |
- | Action area opposite the heading. |
meta |
React.ReactNode |
- | Extra content below description. |
testID |
string |
- | Forwarded to the root Surface stack. |
Inherited props:
No inherited props. PageHeaderProps is declared directly by ZORA.
Section wrapper that optionally renders a SectionHeader.
<PageSection actions={<Button>Refresh</Button>} title="Recent activity">
{content}
</PageSection>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Section title; when absent, no header is rendered. |
description |
React.ReactNode |
- | Passed to the section header. |
actions |
React.ReactNode |
- | Passed to the section header. |
children |
React.ReactNode |
- | Section body. |
testID |
string |
- | Forwarded to the root Surface stack. |
Inherited props:
No inherited props. PageSectionProps is declared directly by ZORA.
Responsive shell with required sidebar, main content, and optional aside.
<SidebarLayout sidebar={navigation} aside={details}>
{content}
</SidebarLayout>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
sidebar |
React.ReactNode |
- | Required left column content. |
children |
React.ReactNode |
- | Main content. |
aside |
React.ReactNode |
- | Optional right column content. |
sidebarWidth |
number |
280 |
Desktop sidebar width. |
asideWidth |
number |
280 |
Desktop aside width. |
testID |
string |
- | Forwarded to the root Surface stack. |
Inherited props:
No inherited props. SidebarLayoutProps is declared directly by ZORA.
Top navigation shell with optional sidebar composition.
<TopbarLayout topbar={topbar} sidebar={sidebar}>
{content}
</TopbarLayout>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
topbar |
React.ReactNode |
- | Required topbar content. |
children |
React.ReactNode |
- | Main content. |
sidebar |
React.ReactNode |
- | Optional sidebar; when present, content is rendered through SidebarLayout. |
testID |
string |
- | Forwarded to the root Surface stack. |
Inherited props:
No inherited props. TopbarLayoutProps is declared directly by ZORA.
Reusable settings shell with page header, sidebar, and content region.
<SettingsLayout actions={<Button>Save</Button>} sidebar={nav} title="Settings">
{content}
</SettingsLayout>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Optional page title; when absent, no page header is rendered. |
description |
React.ReactNode |
- | Header description. |
sidebar |
React.ReactNode |
- | Required settings navigation or context sidebar. |
children |
React.ReactNode |
- | Settings content. |
actions |
React.ReactNode |
- | Header action area. |
testID |
string |
- | Forwarded to Page. |
Inherited props:
No inherited props. SettingsLayoutProps is declared directly by ZORA.
Centered authentication-style shell for sign-in, onboarding, and recovery screens.
<AuthLayout description="Sign in to continue" title="Welcome back">
{form}
</AuthLayout>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Card title. |
description |
React.ReactNode |
- | Card description. |
eyebrow |
React.ReactNode |
- | Card eyebrow. |
children |
React.ReactNode |
- | Form or auth content. |
footer |
React.ReactNode |
- | Card footer. |
testID |
string |
- | Forwarded to the root Surface center. |
Inherited props:
No inherited props. AuthLayoutProps is declared directly by ZORA.
Form field wrapper with rich label composition, description, helper text, and Surface field state.
<FormField helperText="We only use this for sign-in." label="Email">
<Input keyboardType="email-address" />
</FormField>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
React.ReactNode |
- | Required field label. |
description |
React.ReactNode |
- | Rendered under the label. |
helperText |
React.ReactNode |
- | Passed to Surface Field as helperText. |
Inherited props:
Picks these Surface FieldProps: children, disabled, errorText,
invalid, readOnly, required, and testID.
Semantic notice surface with badge eyebrow, optional body, and actions.
<Notice actions={<Button>Review</Button>} title="Publish pipeline ready" tone="success" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Required notice title. |
description |
React.ReactNode |
- | Notice description. |
children |
React.ReactNode |
- | Optional body content. |
actions |
React.ReactNode |
- | Optional action area. |
tone |
ZoraTone |
'primary' |
Drives the badge eyebrow tone. |
testID |
string |
- | Forwarded to the underlying Card. |
Inherited props:
No inherited props. NoticeProps is declared directly by ZORA.
Named composition surface that currently forwards to Card.
<Panel description="Release details" title="Release Candidate">
{content}
</Panel>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Header title. |
description |
React.ReactNode |
- | Header description. |
eyebrow |
React.ReactNode |
- | Small muted text above the title. |
actions |
React.ReactNode |
- | Header action area. |
footer |
React.ReactNode |
- | Footer area below body content. |
children |
React.ReactNode |
- | Panel body. |
tone |
ZoraCardTone |
'default' |
Same tone behavior as Card. |
compact |
boolean |
false |
Same compact behavior as Card. |
testID |
string |
- | Forwarded through Card. |
Inherited props:
No inherited props. PanelProps is declared directly by ZORA.
Reusable section heading with optional eyebrow, description, and actions.
<SectionHeader actions={<Badge>Live</Badge>} title="Activity" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Required heading title. |
description |
React.ReactNode |
- | Supporting copy. |
eyebrow |
React.ReactNode |
- | Small muted text above the title. |
actions |
React.ReactNode |
- | Action area opposite the heading. |
testID |
string |
- | Forwarded to the root Surface stack. |
Inherited props:
No inherited props. SectionHeaderProps is declared directly by ZORA.
Compact settings row with optional metadata, control, and press handling.
<SettingsRow control={<Switch value={enabled} />} title="Notifications" />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Required row title. |
description |
React.ReactNode |
- | Row description. |
meta |
React.ReactNode |
- | Small muted metadata below the row content. |
control |
React.ReactNode |
- | Trailing control or action content. |
onPress |
() => void |
- | Makes the underlying card pressable. |
disabled |
boolean |
false |
Forwarded to the underlying card. |
testID |
string |
- | Forwarded to the underlying card. |
Inherited props:
No inherited props. SettingsRowProps is declared directly by ZORA.
No-data surface with title, optional supporting text, actions, and footer.
<EmptyState
primaryAction={{ label: 'Create project', onPress: createProject }}
title="Nothing here yet"
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Required empty-state title. |
description |
React.ReactNode |
- | Supporting copy. |
eyebrow |
React.ReactNode |
- | Card eyebrow. |
primaryAction |
EmptyStateAction |
- | Primary action button. |
secondaryAction |
EmptyStateAction |
- | Secondary action button; defaults to tone="neutral" and emphasis="soft" when omitted on the action. |
footer |
React.ReactNode |
- | Footer content below actions. |
testID |
string |
- | Forwarded to the underlying card. |
EmptyStateAction:
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
React.ReactNode |
- | Button label. |
onPress |
() => void |
- | Button handler. |
tone |
ZoraTone |
- | Button tone. |
emphasis |
ZoraEmphasis |
- | Button emphasis. |
Inherited props:
No inherited props. EmptyStateProps and EmptyStateAction are declared
directly by ZORA.
Narrow confirmation modal for destructive or high-signal decisions.
<ConfirmDialog
confirmLabel="Archive"
confirmTone="danger"
onCancel={close}
onConfirm={archive}
title="Archive project?"
visible={visible}
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
visible |
boolean |
- | Required modal visibility. |
title |
React.ReactNode |
- | Required dialog title. |
description |
React.ReactNode |
- | Dialog description. |
children |
React.ReactNode |
- | Dialog body. |
confirmLabel |
React.ReactNode |
'Confirm' |
Confirm button label. |
cancelLabel |
React.ReactNode |
'Cancel' |
Cancel button label. |
confirmTone |
ZoraTone |
'danger' |
Confirm button tone. |
confirmEmphasis |
ZoraEmphasis |
'solid' |
Confirm button emphasis. |
busy |
boolean |
false |
Passed to the confirm button as loading. |
closeOnBackdrop |
boolean |
true |
Passed to the underlying modal. |
onConfirm |
() => void |
- | Confirm button handler. |
onCancel |
() => void |
- | Cancel button and modal dismiss handler. |
testID |
string |
- | Forwarded to the underlying modal. |
Confirm dialogs always use Modal with width="narrow".
Inherited props:
No inherited props. ConfirmDialogProps is declared directly by ZORA.
Collapsible section for property groups and settings.
<DisclosureSection title="Advanced Settings">{content}</DisclosureSection>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Section title. |
description |
React.ReactNode |
- | Subheading text. |
defaultOpen |
boolean |
true |
Initial state. |
open |
boolean |
- | Controlled state. |
onOpenChange |
(open: boolean) => void |
- | Toggle handler. |
actions |
React.ReactNode |
- | Extra header actions. |
Side panel that adapts to screen size (inline or overlay).
<ResponsivePanel onOpenChange={setOpen} open={open} title="Inspector">
{content}
</ResponsivePanel>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
open |
boolean |
- | Required visibility. |
onOpenChange |
(open: boolean) => void |
- | Required change handler. |
side |
'left' | 'right' |
'right' |
Layout side. |
desktopMode |
'inline' | 'floating' |
'inline' |
Desktop rendering style. |
mobileMode |
'drawer' | 'modal' |
'drawer' |
Mobile rendering style. |
Dense form field optimized for property panels.
<InspectorField
control={<IconButton icon={{ name: 'refresh-outline' }} label="Reset" />}
label="Opacity"
>
<Input value="100%" />
</InspectorField>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
React.ReactNode |
- | Field label. |
control |
React.ReactNode |
- | Trailing control slot. |
children |
React.ReactNode |
- | Main editor content. |
Inherits all FormField props.
Labeled boolean toggle row.
<SwitchField label="Enable Notifications" onValueChange={setVal} value={val} />Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
React.ReactNode |
- | Required label. |
description |
React.ReactNode |
- | Subheading text. |
value |
boolean |
- | Required state. |
onValueChange |
(value: boolean) => void |
- | Required handler. |
Hierarchical list for navigation and layers.
<TreeView
nodes={[{ id: '1', label: 'Folder', children: [{ id: '2', label: 'File' }] }]}
onSelect={(id) => console.log(id)}
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
nodes |
TreeItemNode[] |
- | Required tree data. |
selectedId |
string |
- | Active node. |
expandedIds |
string[] |
- | Controlled expansion. |
onSelect |
(id: string) => void |
- | Click handler. |
Grid-based selection for palettes and toolboxes.
<TileGrid>
<PaletteItem title="Red" onPress={() => setCol('red')} />
<PaletteItem title="Blue" onPress={() => setCol('blue')} />
</TileGrid>Props
TileGrid props:
| Prop | Type | Default | Notes |
|---|---|---|---|
columns |
number | 'responsive' |
'responsive' |
Grid layout. |
PaletteItem props:
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
React.ReactNode |
- | Item title. |
selected |
boolean |
false |
Highlighted state. |
onPress |
() => void |
- | Click handler. |
Generic visual shell for editing ordered collections.
<CollectionEditor
items={items}
renderItem={({ item }) => <Text>{item.name}</Text>}
onAdd={() => add()}
onRemove={(index) => remove(index)}
/>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
items |
readonly T[] |
- | Required collection. |
renderItem |
(props) => ReactNode |
- | Required item renderer. |
onAdd |
() => void |
- | Add handler. |
onRemove |
(index: number) => void |
- | Remove handler. |
onMove |
(from, to) => void |
- | Reorder handler. |
Interactive pattern for editing a ZoraTheme seed and previewing the result live.
Pass your current theme as value and handle updates through onChange. Wrap both
in a ZoraProvider so the preview area reflects every change immediately.
const [theme, setTheme] = React.useState<ZoraTheme>(zoraDefaultTheme);
const [mode, setMode] = React.useState<ZoraThemeMode>('light');
return (
<ZoraProvider theme={theme} initialMode={mode}>
<ThemeComposer
value={theme}
onChange={setTheme}
mode={mode}
onModeChange={setMode}
onSubmit={(t) => saveTheme(t)}
/>
</ZoraProvider>
);Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
value |
ZoraTheme |
- | Required controlled theme seed. |
onChange |
(theme: ZoraTheme) => void |
- | Required. Fires on every valid change. |
mode |
ZoraThemeMode |
- | Current light/dark mode shown in the mode toggle. |
onModeChange |
(mode: ZoraThemeMode) => void |
- | Called when the user switches the mode toggle. |
onSubmit |
(theme: ZoraTheme) => void |
- | Optional. Renders an "Apply theme" button if set. |
testID |
string |
- | Forwarded to the root element and child test points. |
Theme provider that creates the ZORA theme and passes it to Surface
ThemeProvider.
<ZoraProvider initialMode="dark">
<App />
</ZoraProvider>Pass a theme seed to define your app theme:
<ZoraProvider
initialMode="dark"
theme={{
id: 'studio',
name: 'Studio',
primaryColor: '#0f766e',
harmony: 'analogous',
colorTone: 'jewel',
}}
>
<App />
</ZoraProvider>Props
ZORA props:
| Prop | Type | Default | Notes |
|---|---|---|---|
children |
React.ReactNode |
- | Required app content. |
theme |
ZoraTheme |
zoraDefaultTheme |
App-facing theme seed for ZORA. |
initialMode |
'light' | 'dark' |
'light' |
Initial theme mode passed to Surface. |
Inherited props:
No inherited props. ZoraProviderProps is declared directly by ZORA.
Creates a Surface-compatible ThemeConfig from a ZORA theme seed.
const themeConfig = createZoraThemeConfig({
id: 'studio',
name: 'Studio',
primaryColor: '#0f766e',
harmony: 'analogous',
colorTone: 'jewel',
});API
function createZoraThemeConfig(theme?: ZoraTheme): ThemeConfig;Default ZORA theme seed.
Value
const zoraDefaultTheme: ZoraTheme = {
id: 'zora',
name: 'ZORA',
primaryColor: '#0f766e',
harmony: 'analogous',
colorTone: 'jewel',
};A complete Expo showcase lives in examples/expo-showcase. It renders the
current ZORA components, layouts, patterns, and theme entry points, including
light/dark mode through AppShell.
Run it locally:
cd examples/expo-showcase
bun install
bun run webThe example imports @ankhorage/zora and demonstrates the package API in
examples/expo-showcase/App.tsx.
Version history is maintained in CHANGELOG.md.
MIT