Skip to main content

Context hooks

What a component rendered by the schema can read about its surroundings — which admin it is in, which view, which field, and which record the whole screen belongs to.

These are the hooks a custom field, input or box reaches for. Inside the generated views the contexts are already in place; outside them the ones that throw will say so.

HookGives youOutside its provider
useSchemaRootContextThe resolved providers, service schemas and identityThrows
useAdminConfigThe app-shell configurationThrows
useIconsiconsMap and the getIcon resolverReturns an empty map
useViewSchemaContextThe view being rendered, plus readOnlyThrows
useFieldSchemaContextThe schema of the field being renderedThrows
useRootRecordContextThe record the screen belongs toReturns undefined
useFormInputSourcesContextThe sources registered on the current formReturns empty defaults
useFormInputSourcesRegistrationregister / unregister alone, without the listReturns undefined callbacks
useUnsavedChangesWhether the form has unsaved changesReturns false
useUnsavedChangesControlRead or set that flag without subscribingReturns a no-op pair
caution

The single useAdminContext of earlier versions no longer exists. The schema-driven half of it is useSchemaRootContext, the app-shell half is useAdminConfig, and the icon resolver moved to useIcons.

useSchemaRootContext​

The schema-driven root of the admin, resolved: every provider together with its default (fieldProvider / defaultFieldProvider, and the same pair for inputs, boxes, buttons and views), the schemaProvider, the built dataProvider and authProvider, the fetched servicesSchema with refetchSchema, the serviceConfigMap, the declared resources, and the flags defaultRowAction, rowTooltip, hasDashboard, isLoaded.

const {servicesSchema, isLoaded, defaultRowAction, userIdentity} = useSchemaRootContext();

userIdentity is held above React Admin's own <Admin> and kept current through setUserIdentity across sign-ins, sign-outs and impersonations — it is the identity the schema fetches and the per-user store are keyed by.

An admin assembled by hand supplies both itself — see SchemaRootContextProvider.

useAdminConfig​

Everything the app shell was configured with: logo, menu, availableLanguages, search, marketing, status, breadcrumbs, arrangement, contentMaxWidth, columnSelector, onLogout, updateIdentity, changePassword, navigationGuard, draftEnabled, defaultPerPage, notificationAutoHideDuration and iconsMap.

It is shared by both entry points — SchemaAdmin and the schema-agnostic BaseAdmin — which is why the layout components can read it without taking props.

tip

The current locale is not here. It lives in the React Admin store; read it with useLocaleState() from react-admin.

useIcons​

const {iconsMap, getIcon} = useIcons();

const icon = getIcon('status', 'published', 'orderStatus');

getIcon(source, value, iconsKey) resolves a value against the iconsMap — the entry may be a map of value to element or a function of (source, value). It returns undefined when iconsKey is missing from the map, which is how ChoicesField falls back to a plain chip.

useViewSchemaContext​

The view currently rendering:

NameTypeDescription
viewSchemaViewSchemaThe view's own schema
methodSchemaMethodSchemaThe endpoint schema its fields come from
resourcestringResource in "service/resource" form
recordIdIdentifierPresent on detail views
actionNamestringPresent when the view belongs to an action
readOnlybooleanDerived — see below

readOnly is the flag the boxes use to decide between displaying and editing — read it instead of comparing viewSchema.type yourself. It is true for list and show views, and also for an action view whose root box is read-only (a routed action that only presents data, with no form to submit).

useFieldSchemaContext​

The FieldSchema of the field being rendered — its type, format, label, validation and options. This is what a custom field or input reads instead of taking everything through props.

useRootRecordContext​

The record the whole screen is about, as opposed to the record of the row or array item currently in scope. Inside a list box or an array box, react-admin's useRecordContext gives you the inner record; this one still gives you the outer one.

const order = useRootRecordContext<Order>();

It returns undefined outside a detail view rather than throwing, so a component that works in both places does not need a guard.

useFormInputSourcesContext​

The list of input sources registered on the current form. Array boxes register their target so the form knows the field exists even before an item is added.

const {sources} = useFormInputSourcesContext();

It re-renders the caller on every registration, because that is when the list changes. Use it only where you need the list itself; to register an input, use useFormInputSourcesRegistration below.

The hook also returns register / unregister, so an existing call site keeps working — but reaching for them here subscribes you to the list for nothing.

useFormInputSourcesRegistration​

register / unregister on their own, for an input that only adds itself to the form's source list. Its value never changes, so subscribing costs nothing and a registration re-renders no one.

const {register, unregister} = useFormInputSourcesRegistration();

Both are undefined outside a form — check before calling, as the built-in boxes do.

useUnsavedChanges​

Whether the form currently has unsaved changes. Re-renders the caller whenever that flips, so use it only where you render something off the value — a badge, a disabled state.

const {hasUnsavedChanges} = useUnsavedChanges();

useUnsavedChangesControl​

The same flag, read and written without subscribing — the value of this context never changes.

const {getHasUnsavedChanges, setHasUnsavedChanges} = useUnsavedChangesControl();

getHasUnsavedChanges() returns the value current at call time, so call it from an event handler or an effect, never during render. This is what a button that guards navigation should use: it needs the flag when it is clicked, not on every keystroke that changes it.

useGetTargetValues​

The foreign keys a record being created should inherit from where the user came from — creating an order from a customer's detail gives {customer: 42}.

const targetValues = useGetTargetValues();
// → {customer: 42} | undefined

It is resolved from two sources, in order:

  1. the _target query parameter of the current view, parsed as JSON — malformed JSON yields undefined rather than throwing,
  2. otherwise the last parent resource descriptor that carries a target, which is what a list box pushes when it renders a related list.

Use it to pre-fill a hand-built create form the same way the generated one does.

See also​