Differences from React
Where @chelone/vue departs from the React pages, so you know which code does not carry over.
Most pages in these docs show React code. @chelone/vue has the same
components, controllers and hooks, so a page still describes the behaviour. This
page lists where the Vue code is written differently. Setup is on the
Vue setup page.
The general mapping:
- Props are kebab-case in templates:
:data-provider,:query-client. - A React callback prop such as
onConfirmis an emitted event:@confirm. - A
ReactNodeprop is a slot:#layout,#dashboard,#error. - A component prop takes the component itself, not a render function:
:list="PostList". - A composable returns
Refs where the React hook returns plain values.
A component page's props table follows the React and Vue switch on the page. Set
to Vue, it lists the props, emitted events and slots @chelone/vue declares for
that component, which is not always the React list with the names changed.
The admin
| React | Vue | React page |
|---|---|---|
<Admin router={...}> swaps the router adapter. | There is no router prop and no router swap. <Admin> uses the vue-router the app installs. | Swapping the router |
The children can be a function that receives permissions. | The default slot takes no arguments. | Auth, basename and permissions |
<Admin.Title> and the title prop set the admin title. | There is no <Admin.Title> and no title slot. | Admin |
With no layout given, <Admin> renders the routes with no layout. | A default layout renders when no #layout slot is given. | The layout slot |
The Zod registry prop is resources. | The Zod registry prop is registry. resources is an array of view definitions, the way to register a resource without a <Resource> child. | The resources prop |
<CustomRoutes> children add routes. | customRoutes is an array prop, read once. | Custom Routes |
The error fallback receives { error, errorInfo, resetErrorBoundary }. | The #error slot receives { error, info, reset }. info is Vue's description of where the error was thrown. | Error |
ResourceDefinition takes options, so resources group in the menu and carry a label override. | ResourceDefinition has no options: the menu is one flat group, and a resource label comes from the translation key or the humanized name. | Resource |
The full prop list for <Admin> and <Resource> is on the
Vue setup page.
Forms and hooks
| React | Vue | React page |
|---|---|---|
<TabbedForm.Tab> and <WizardForm.Step> are statics on the form. | TabbedFormTab and WizardFormStep are separate components, imported from @chelone/vue. | Tabbed Form, Wizard Form |
useStoreItem(key, default) returns [value, setter] and follows a changing key. | useStoreItem returns [Ref, setter]. The key and default are read once, in setup. | None |
A field or input label is a ReactNode. | label is a string, or false to hide it. An input takes no label markup. <FieldLabelText> renders its default slot as the label, for a label you build yourself. | Text Input |
<FilterForm> selects the displayed filters with alwaysOn and a remove control per input. | <FilterForm> shows the inputs slotted into it. There is no alwaysOn and no displayed-filter selection. | Filter Form |
Components
| React | Vue | React page |
|---|---|---|
<Confirm> takes onConfirm and onClose, and a node as content. | <Confirm> emits confirm and close, and takes a string as content. Its default slot holds a body that is not translated. | Confirm |
<BooleanField> takes TrueIcon and FalseIcon. | <BooleanField> has no TrueIcon or FalseIcon props. It draws a built-in check or cross, styled through class. | Boolean Field |
<FileInput> and <ImageInput> use react-dropzone. | They use native drag and drop. The value shape is the same: { rawFile, src, title } for a dropped file. | File Input, Image Input |
<Notification> renders through sonner. | <Notification> is a dependency-free toaster, a stack at the bottom centre with its own close button. | Notification |
<ThemeModeToggle> opens a dropdown of modes. | <ThemeModeToggle> is one button. Each click cycles light, dark, system. | Theme Mode Toggle |
<IconButtonWithTooltip> shows a styled tooltip. | <IconButtonWithTooltip> shows the native title, because the Vue ui slice has no Tooltip. Its label is also the aria-label; a #label slot stands in for a non-string label. | Icon Button With Tooltip |
<SimpleList> takes function props such as primaryText. | <SimpleList> takes scoped slots such as #primary-text, each given { record, id }. | Simple List |
<SimpleFormIterator> is a child of <ArrayInput>. | There is no <SimpleFormIterator>. <ArrayInput> takes disableAdd, disableRemove, inline and the rest as props, with the #add-button, #remove-button and #reorder-buttons slots. | Simple Form Iterator |
<TabbedShowLayout>, <TranslatableInputs> and <TranslatableFields> draw their tabs with ui/tabs. | They draw native buttons with role="tab". The tab child of <TabbedShowLayout> is TabbedShowLayoutTab, imported from @chelone/vue. | Tabbed Show Layout, Translatable Inputs, Translatable Fields |
<TranslatableInputs> and <TranslatableFields> take a selector element. | They take a #selector slot. | Translatable Inputs, Translatable Fields |
<RefreshIconButton> shows a styled tooltip. | <RefreshIconButton> shows the native title, and its label is also the aria-label. | Refresh Icon Button |
<BulkEditDrawer> opens a Sheet. | <BulkEditDrawer> opens an inline panel that is not teleported. | Bulk Edit Drawer |
<FilterLiveSearch> builds on FilterLiveForm. | <FilterLiveSearch> builds on <FilterForm>, because Vue has no FilterLiveForm. | Filter Live Search |
<ColumnsButton> opens a Popover. | <ColumnsButton> shows its panel inside a DropdownMenu. The panel holds plain rows, so it stays open while you switch several columns. | Columns Button |
<TreeList> takes the onSelect, loading and empty props. | <TreeList> emits select and takes the #loading and #empty slots. With no select listener a row navigates, as React does with no onSelect. | Tree List |
<PivotGrid> takes the loading and empty props. | <PivotGrid> takes the #loading and #empty slots. | Pivot Grid |
<PivotGrid> takes a format that returns a node. | <PivotGrid> takes a format that returns a string, so a cell is always text. | Pivot Grid |
<RecordTimeline> takes the loading and empty props. | <RecordTimeline> takes the #loading and #empty slots. | Record Timeline |
<CalendarList> takes the onSelectEvent, onSelectSlot and onDrop props. | <CalendarList> emits select-event, select-slot and drop. A drop listener makes month-view events draggable. | Calendar List |
<CalendarList> takes the eventRenderer and headerRenderer props. | <CalendarList> takes the #event and #header slots. | Calendar List |
<KanbanBoard> takes an onSelectCard prop. | <KanbanBoard> emits select-card. With no select-card listener a card navigates, as React does with no onSelectCard. | Kanban Board |
<KanbanBoard> takes a cardRenderer prop. | <KanbanBoard> takes the #card slot, given { record }. | Kanban Board |
<ApprovalQueue> takes a rowExtra prop, a function of the record. | <ApprovalQueue> takes the #extra slot, given { record }. | Approval Queue |
<StatusTransitionButton> takes an onTransition prop. <DualApprovalButton> takes only props. | <StatusTransitionButton> emits a transition event with the same (from, to, record) arguments. <DualApprovalButton> takes the same props. | Status Transition Button, Dual Approval Button |
<CommandMenu> composes cmdk's Command with a teleported dialog. | <CommandMenu> composes the native ui/command family with an inline dialog that is not teleported. | Command Menu |
<Assistant> confirms a tool in a Radix Dialog that shows the arguments in a <pre>. | <Assistant> confirms a tool in the inline <Confirm>, which is not teleported. It passes the arguments in <Confirm>'s default slot, in a <pre>. Its icons are inline SVG. The props are the same. | Assistant |
<DiffViewer> takes formatters, a renderer per source that returns a node. | <DiffViewer> takes the #value slot, given { source, value, side } with side either before or after. | Diff Viewer |
<DiffViewer> takes labels whose values can be nodes. | <DiffViewer> takes labels whose values are strings. | Diff Viewer |
<PermissionMatrix> takes value and onChange. | <PermissionMatrix> is a v-model: modelValue in and update:modelValue out with the whole next value. It takes class where React takes className. | Permission Matrix |
<InPlaceEditor> takes children for the shown value and editor for the input. | <InPlaceEditor> takes the default slot for the shown value and the #editor slot for the input. | In Place Editor |
<InPlaceEditor> takes onSuccess and onError props. | <InPlaceEditor> emits success with the saved record and error with the failure. | In Place Editor |
<Configurable> takes an editor node prop, and <InspectorButton> takes the shadcn button props with an onClick. | <Configurable> takes the #editor slot, and <InspectorButton> takes label, class and disabled, has an #icon slot and emits click. Both take class where React takes className. | Inspector |
<OnboardingTour> takes an onComplete prop, called with "finished" or "skipped". | <OnboardingTour> emits complete with the same two values. | Onboarding Tour |
<OnboardingTour> steps take a title and content that are nodes. | A step's title and content are strings. A #step slot, given { step, index }, replaces both. | Onboarding Tour |
<TrendChart> and <BarChart> plot the row's xField value on the x axis. | They plot the row index and label each tick with that row's xField, so any x value keeps its order. With more than 7 rows only every step-th tick is labelled. | Trend Chart, Bar Chart |
<TrendChart>'s xTickFormatter formats the x axis ticks. | It formats the tooltip's row label too: the axis and the crosshair share one function. | Trend Chart |
<TrendChart> and <BarChart> show their tooltip through recharts' <ChartTooltip>. | They show it through unovis' crosshair: VisCrosshair carries an HTML template and VisTooltip renders it. | Trend Chart, Bar Chart |
<DonutChart> shows its tooltip through recharts' <ChartTooltip> as well. | It has no crosshair. VisTooltip takes a triggers map keyed on Donut.selectors.segment, so the tooltip follows the hovered segment. | Donut Chart |
<TrendChart>'s tooltipFormatter returns text recharts renders as a node. | It returns text that goes into the crosshair's HTML string. | Trend Chart |
<DonutChart>'s height sizes the chart, and the ring is 30% of the radius whatever it is. | height sizes the chart and the ring: the arc is 15% of height wide. | Donut Chart |
<TrendChart>, <BarChart>, <DonutChart> and <MetricCard> take className. | They take class. | Trend Chart, Bar Chart, Donut Chart, Metric Card |
useGeoJsonSource(map, sourceId, data, style) takes plain values. | useGeoJsonSource(sourceId, data, style) takes refs or getters and reads the map from the surrounding <MapCanvas>. | None |
Theme storage differs too: the Vue <ThemeProvider> always uses localStorage
and useTheme() returns Refs. The note under
Themes has the details.
Maps
The maps add-on has three entries: @chelone/vue/maps for map display,
@chelone/vue/maps/draw for the shape inputs and @chelone/vue/maps/osm for
geocoding and OpenStreetMap import. They export the names of the React
subpaths. The Vue ui slice lacks some of the components the React inputs build
on, so <GeocodingInput> is a native combobox, <SimplifyInput> uses a native
range input with two buttons for its quality, and <DrawToolbar> draws inline
SVG icons. See Maps for the guide.
Add-ons
The Monaco components are an add-on, imported from @chelone/vue/monaco or
installed from the registry as @chelone/monaco. The Markdown components are
another, imported from @chelone/vue/mdx-editor or installed as
@chelone/mdx-editor. The charts are a third: <TrendChart>, <BarChart> and
<DonutChart> come from @chelone/vue/charts and need @unovis/vue and
@unovis/ts, where React has @chelone/react/charts and recharts.
<MetricCard> is not part of it: it ships in both base packages and draws no
chart. The rich text components are a fourth, imported from
@chelone/vue/rich-text-input or installed as @chelone/rich-text-input. The
block editor is a fifth: <BlockEditorInput>, <BlockDocField> and
defineBlock come from @chelone/vue/block-editor and need the @tiptap/*
packages, @dnd-kit/vue and @dnd-kit/dom for the block drag handle, and
@unovis/vue and @unovis/ts for its chart block. That block draws with the
/charts components of its own adapter: <TrendChart>, <BarChart> and
<DonutChart> from @chelone/vue/charts here, and the same three from
@chelone/react/charts in React, where the block needs recharts instead.
<BlockEditor> emits change with the document, and
<BlockDocField> takes a string empty with a #empty slot where React takes
an empty node. The inspector is a sixth: <Inspector>, <InspectorButton>,
<Configurable>, <ConfigurableInputs> and <SortableFieldsSelector> come
from @chelone/vue/inspector and need @dnd-kit/vue, where React has
@chelone/react/inspector and @dnd-kit/react.
| React | Vue | React page |
|---|---|---|
<MonacoJsonInput> and <MonacoJsonField> use @monaco-editor/react, and take className. The input also takes editorClassName. | They use @guolao/vue-monaco-editor, and take class. The input also takes editor-class. <MonacoJsonInput> has no id, resource, isRequired, format, parse or alwaysOn prop and emits no events. | Monaco Json Input, Monaco Json Field |
<MdxInput> and <MdxField> use @mdxeditor/editor and the mdxeditor-dark class. <MdxInput> has a fixed toolbar and takes mdxProps, whose plugins replace the defaults. <MdxField> has no toolbar and takes plugins and the other editor props directly. | They wrap Milkdown's Crepe editor, because MDXEditor is React only. The input's toolbar floats over a selection, crepeConfig replaces mdxProps and plugins on both components, and a theme file replaces the dark class. They take class, and <MdxInput> has no id, resource, isRequired, format, parse or alwaysOn prop. | Mdx Input, Mdx Field |
<RichTextInput> uses @tiptap/react and takes toolbar. <RichTextToolbar> reads the editor context. <RichTextField> accepts a node for empty. | The input uses @tiptap/vue-3 and a #toolbar slot receiving { editor }. The toolbar takes an editor prop. The field takes a string for empty or a #empty slot. Both components use class. | Rich Text Input, Rich Text Field |
<BlockEditorInput> takes className, a node label and a node helperText, and <BlockDocField> takes a node as empty. <BlockEditor> takes onChange. | They take class, a label that is a string or false, and a helper-text string. <BlockEditorInput> has no id, resource, isRequired, format, parse or alwaysOn prop. <BlockEditor> emits change with the document, and <BlockDocField> takes a string empty plus a #empty slot. Both entries ship the four default blocks and the three data blocks (dataBlocks), and both move a block with a drag handle; a chart block draws with unovis here and recharts in React. | Block Editor Input, Block Doc Field |
What this page leaves out
The list is the differences you write differently. Port details with no API effect, such as how a dropdown menu positions itself, are not listed.