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>
);
}
Component Groups
- Forms:
Form,Field,Input,Textarea,Select,Combobox,Switch,Checkbox,DatePicker,ColorPicker - Data:
DataTable,Pagination,Table,Calendar,Chart,Timeline,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