SDK surface
Everything a plugin may use, exposed on window.AdminSDK. Nothing outside this list is a
stable contract.
const SDK = window.AdminSDK;
Runtime#
| Key | What it is |
|---|---|
SDK.version |
SDK version. Compare against your plugin's requiresSdk(). |
SDK.React |
The host's React. Never import React yourself. |
SDK.ReactDOM |
The host's ReactDOM. |
SDK.router |
Router instance — navigate(), hooks, Link. |
HTTP#
const { Http, factory, fetcher } = SDK.http;
Pre-configured with the API base path, credentials and CSRF handling. Use it instead of bare
fetch, otherwise the request goes out without the session cookie and returns 401.
Store#
const { store, dispatch, useSelector, Actions,
createStore, configureStore, combineSlices, createSlice,
Subscriber, createStoreOrder, connectStore } = SDK.store;
The shared host store plus a toolkit for building an independent store or contributing a slice. Using the host's toolkit rather than bundling your own keeps a single store instance across the whole admin.
UI primitives#
const { Button, Badge, Card, CardContent, Input, Label, Switch, Textarea,
Checkbox, Skeleton,
Dialog, DialogContent, DialogHeader, /* … */
Select, SelectTrigger, SelectContent, /* … */
DropdownMenu, Tabs, Collapsible /* … and their parts */ } = SDK.ui;
Components#
| Component | Purpose |
|---|---|
Container |
Standard page frame — max width, padding, title, breadcrumb. |
DataTable |
List table: columns, search, sort, pagination, multi-select, bulk delete, loading/error/empty states, toolbar. |
CanRender |
Renders children only if the user holds the permission. |
DynamicIcon |
Lucide icon by string name, without importing lucide-react. |
RichEditor |
Tiptap rich text. Lives in the host because Tiptap pulls React. |
ListRepeater |
Repeating sub-records: add, edit, remove, reorder. |
StringListEditor |
Editable list of plain strings. |
FormFieldsBuilder |
Builder for dynamic form definitions. |
RichTextField |
Form-bound rich text field. |
MediaThumbPicker |
Thumbnail picker. |
NavTreeEditor |
Drag-and-drop tree editor for navigation. |
LangSwitcher |
Locale switcher for translatable forms. |
PluginSlot |
Publishes an insertion point in your own UI. |
PluginComponent |
Renders a component published by another plugin, with a fallback. |
Hooks#
| Hook | Returns |
|---|---|
useCrumb() |
Sets the breadcrumb for the current screen. |
useListQuery(url) |
{ rows, loading, error, query, setQuery, refresh } — pairs with DataTable. |
useConfirmDelete() |
Confirmation dialog plus the delete request. |
useCan() |
can(permission) for the current user. |
useActiveLanguages() |
Active locales from the language plugin. |
useLocale() |
Current admin locale. |
usePluginComponent(name) |
A published component, or null. |
usePluginSlot(name) |
Components registered into a slot, ordered. |
Utilities#
const { cn, money, num, date } = SDK.utils;
cn merges class names. The formatters exist so plugins do not each bundle their own copy
of a formatting library and drift apart on output.
SDK.toast.success('Saved');
SDK.toast.error('Something went wrong');
const { errorMessage, fieldErrors } = SDK.lib;
errorMessage(error) turns an API error envelope into a string; fieldErrors(error) turns
it into a per-field map for form display.
Drag and drop#
const { DndContext, sortable, utilities } = SDK.dnd;
dnd-kit re-exported from the host. Importing it directly would give your plugin a second copy with its own React context, and drag events would not reach the host's handlers.
Registration#
SDK.registerPlugin(registration) // routes, slots, components
SDK.registerComponent(name, component) // publish one component, independent of registerPlugin
SDK.getComponent(name) // imperative lookup