Overview
@editora/ui-react provides React-native ergonomics on top of Web Components from @editora/ui-core. It includes typed wrappers, hooks for common workflows, and providers for dialogs and theme state.
Installation
npm install @editora/ui-react @editora/ui-core
Peer dependencies: react, react-dom.
Quick Start
import { Button, Input, ThemeProvider } from '@editora/ui-react';
export function App() {
return (
<ThemeProvider>
<div style={{ display: 'grid', gap: 12, maxWidth: 360 }}>
<Input name="title" label="Title" placeholder="Untitled" clearable />
<Button variant="primary">Save</Button>
</div>
</ThemeProvider>
);
}
Import Rule
Prefer package-root imports from
@editora/ui-react. If you deep-import wrappers directly, ensure @editora/ui-core is imported first so custom elements are registered.
Providers and Hooks
| API | Type | Use Case |
|---|---|---|
ThemeProvider, useTheme |
Provider + hook | Token-based theming and persisted theme state. |
DialogProvider, useDialog |
Provider + hook | Promise-based confirm/prompt dialog workflows. |
AlertDialogProvider, useAlertDialog |
Provider + hook | Destructive/alert flow confirmations with accessibility defaults. |
useForm |
Hook | Validation, submit, dirty-state, reset, and value extraction from wrapped forms. |
Common Patterns
1. Form + useForm
import { Form, Field, Input, Button, useForm } from '@editora/ui-react';
export function ProfileForm() {
const { ref, submit, validate, getValues, reset, isDirty } = useForm();
return (
<Form
ref={ref}
autosave
guardUnsaved
onSubmit={(values) => console.log('submit', values)}
onInvalid={(errors) => console.log('invalid', errors)}
>
<Field label="Full name" required>
<Input name="fullName" required />
</Field>
<Field label="Email" required>
<Input name="email" type="email" required />
</Field>
<Button onClick={() => submit()} disabled={!isDirty()}>Submit</Button>
<Button variant="secondary" onClick={() => reset()}>Reset</Button>
<Button variant="secondary" onClick={() => console.log(getValues())}>Values</Button>
</Form>
);
}
2. Dialog providers
import { DialogProvider, useDialog, AlertDialogProvider, useAlertDialog, Button } from '@editora/ui-react';
function Actions() {
const dialog = useDialog();
const alerts = useAlertDialog();
return (
<div style={{ display: 'flex', gap: 8 }}>
<Button onClick={async () => {
const res = await dialog.confirm({ title: 'Archive project?' });
console.log(res);
}}>Confirm</Button>
<Button variant="secondary" onClick={async () => {
const res = await alerts.prompt({ title: 'Rename' });
console.log(res);
}}>Prompt</Button>
</div>
);
}
export function DialogExample() {
return (
<DialogProvider>
<AlertDialogProvider>
<Actions />
</AlertDialogProvider>
</DialogProvider>
);
}
3. Data table workflows
import { DataTable, Pagination } from '@editora/ui-react';
import { useState } from 'react';
export function UsersTable() {
const [page, setPage] = useState(1);
return (
<div style={{ display: 'grid', gap: 10 }}>
<DataTable
sortable
selectable
page={page}
pageSize={10}
paginationId="users-pager"
onPageChange={(d) => setPage(d.page)}
onSortChange={(d) => console.log('sort', d)}
onRowSelect={(d) => console.log('rows', d.indices)}
>
{/* table markup */}
</DataTable>
<Pagination id="users-pager" page={String(page)} />
</div>
);
}
4. Gantt planning workspace
Gantt provides an interactive project timeline for release plans, delivery roadmaps, and dependency-heavy schedules. It supports task, summary, and milestone rows; baselines; critical tasks; split segments; dependency links; drag/resize editing; keyboard selection; and virtualized rendering for large plans.
import { Gantt, type GanttLink, type GanttTask } from '@editora/ui-react';
import { useState } from 'react';
const initialTasks: GanttTask[] = [
{
id: 'foundation',
label: 'Foundation build',
start: '2026-02-01',
end: '2026-02-18',
progress: 68,
baselineStart: '2026-01-29',
baselineEnd: '2026-02-14',
critical: true
},
{
id: 'launch',
label: 'Launch milestone',
start: '2026-02-28',
type: 'milestone',
tone: 'success'
}
];
const links: GanttLink[] = [
{ id: 'foundation-launch', source: 'foundation', target: 'launch', type: 'e2s' }
];
export function ReleasePlan() {
const [tasks, setTasks] = useState(initialTasks);
return (
<Gantt
tasks={tasks}
links={links}
zoom="week"
sort="start"
barVariant="soft"
onTaskChange={({ id, start, end }) => {
setTasks((items) => items.map((task) => (
task.id === id ? { ...task, start: start ?? task.start, end: end ?? task.end } : task
)));
}}
onTaskDelete={({ id }) => setTasks((items) => items.filter((task) => task.id !== id))}
onLinkSelect={(detail) => console.log('dependency selected', detail)}
/>
);
}
- Dependency types:
e2s,s2s,e2e, ands2e. - Bar variants:
solid,soft,striped,outline, andglass. - Scale support: automatic row virtualization for large schedules, including the 10,000-task Storybook example.
Component Groups
- Forms:
Form,Field,Input,Textarea,Select,Combobox,Switch,Checkbox,DatePicker,ColorPicker - Data:
DataTable,Pagination,Table,Calendar,Chart,Timeline,Gantt,Progress - Overlay:
Dialog,AlertDialog,Popover,Tooltip,Dropdown,Drawer - Layout:
Layout,Sidebar,Tabs,Grid,Flex,Container,Section
Theming
import { ThemeProvider } from '@editora/ui-react';
<ThemeProvider
tokens={{
colors: { primary: '#0f766e', text: '#0f172a', background: '#ffffff' },
radius: '10px'
}}
storageKey="my-app.theme"
>
{/** app */}
</ThemeProvider>
SSR and StrictMode Notes
- Providers are SSR-safe and create host nodes on client mount.
- Promise dialog providers are StrictMode-safe and clean up on unmount.
- Avoid calling custom element imperative methods until component mount is complete.
Production Guidance
- Keep root imports from
@editora/ui-reactto avoid registration drift. - Batch expensive state updates around large table operations.
- Prefer declarative props over direct DOM mutation of wrapped components.
Related Docs
- @editora/ui-core for underlying custom elements and low-level APIs
- @editora/react-icons for React icon provider and components