Pimcore Studio UI SDK Hooks: A Practical Guide for Developers
If you've been building Pimcore plugins for a while, you're probably familiar with the old approach: register an AdminAssetsSubscriber to inject your JavaScript into the admin, override source code methods, extend PHP services, and patch ExtJS components. It worked, but it was fragile - there was always a risk present that the next Pimcore version will make your custom code unusable.
The new Pimcore Studio UI Bundle changes that story on the frontend entirely. Instead of injecting scripts, you can now work with a set of well-defined React hooks that give you access to everything Studio is already doing: its element editors, asset and data object state, navigation, modals, and more. Your plugin registers itself into Studio at boot time, and from that point on you can interact with the UI through the hook API.
As of now, the official Pimcore documentation provides an overview and reference for locating and importing the available SDK exports. However, if you're just getting started with Pimcore Studio or are new to React, this information can feel overwhelming. This guide provides a single, easy-to-navigate, reference that lists all currently available hooks along with their general purpose.
This reference covers 71 hooks across 9 modules, based on SDK version 0.6.30.
Pimcore Studio Series
If you're exploring Pimcore Studio, the following articles cover different aspects of the platform:
- Pimcore Studio overview → introduction to the new interface and overall concept
- Pimcore Studio features → key capabilities and improvements in the Studio UI
- Pimcore Studio Classic UI deprecation and migration path → what changes with the transition and how to approach migration
- How Pimcore Studio UI changes daily work → practical impact on day-to-day usage
While the articles above focus on usage, features, and migration, this guide is focused on extending Pimcore Studio through the SDK.
React Hooks in the Context of Pimcore Studio
If you're coming from a PHP or backend background, React Hooks might be a new concept.
In React, a hook is a function that lets a component “hook” into shared state, side effects, or external systems. Introduced in React 16.8, hooks replaced the older class component pattern and made it much easier to share logic between components.
React comes with several built-in Hooks like useState, useContext, and useEffect. However, it also offers the option to create your own custom Hooks for your application’s needs. With the Pimcore Studio SDK, you get custom hooks built to help you extend and work seamlessly with Pimcore’s existing logic.
In the context of Studio UI, that means you don't need to know how Pimcore manages its Redux store or RTK Query cache internally. You just call useAssetDraft(id) and get back the asset state, or call useDelete('asset') and get back a ready-made delete action and context menu item. The hooks handle the complexity, you handle the product logic.
How the Hooks Are Organised
The hooks are grouped into modules that roughly mirror the concerns of the UI itself:
- components: UI primitives: toasts, notifications, modals, and the element tree
- app / modules/app: translations, system settings, and main navigation
- modules/element: the shared abstraction that powers every element type (assets, data objects, documents): context, draft state, CRUD actions, copy/paste, locking, publishing
- modules/data-object: data-object-specific state, save operations, custom layouts, language selection
- modules/asset: asset-specific state, downloads, thumbnail management
- modules/user: user and role management editors
- modules/widget-manager: programmatic control of Studio's FlexLayout panel system
- utils: general-purpose React helpers: resize observation, intersection detection, server-sent events, and more
High-Level vs Low-Level Hooks
You'll notice two layers throughout the API.
High-level hooks like useAssetDraft or useDataObjectDraft give you everything you need to read an element's current state in one call:
const { asset, isLoading, isError } = useAssetDraft(id)
Underneath them sit low-level draft hooks like useCustomMetadataDraft or useImageSettingsDraft. These are designed for building custom editors that plug directly into Studio's Redux store. Most plugin authors won't need them, but if you're building a fully custom editor tab, they give you fine-grained control over exactly which slices of state you read and mutate.
@pimcore/studio-ui-bundle/components
- useMessage
Returns an Ant Design MessageInstance for showing inline toast messages (success, error, loading, etc.).
import { useMessage } from '@pimcore/studio-ui-bundle/components'
const useMessage: (messageConfig?: ConfigOptions) => MessageInstance
- useNotification
Returns a tuple with an Ant Design NotificationInstance for showing corner notifications.
import { useNotification } from '@pimcore/studio-ui-bundle/components'
const useNotification: () => readonly [NotificationInstance]
- useModal
Provides controlled modal state with render helper.
import { useModal } from '@pimcore/studio-ui-bundle/components'
const useModal: (config?: { type: string }) => IUseModalReturnType
interface IUseModalReturnType {
renderModal: (props: IModalProps) => React.JSX.Element;
showModal: () => void;
handleOk: () => void;
handleCancel: () => void;
closeModal: () => void;
}
- useAlertModal
Programmatically opens alert-style modals (info, error, warn, success).
import { useAlertModal } from '@pimcore/studio-ui-bundle/components'
const useAlertModal: () => {
info: (props: ContentAware) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
error: (props: ContentAware) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
warn: (props: ContentAware) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
success: (props: ContentAware) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
}
- useFormModal
Programmatically opens form modals with input, textarea, confirm, or upload variants.
import { useFormModal } from '@pimcore/studio-ui-bundle/components'
function useFormModal(): {
input: (props: InputFormModalProps) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
textarea: (props: TextareaFormModalProps) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
confirm: (props: ModalFuncProps) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
upload: (props: UploadFormProps) => { destroy: () => void; update: (configUpdate: ConfigUpdate) => void };
}
- useElementTree
Controls the element tree state imperatively (expand, page, search, select).
import { useElementTree } from '@pimcore/studio-ui-bundle/components'
const useElementTree: () => {
setLoading: (nodeId: string, loading: boolean) => void;
setFetching: (nodeId: string, isFetching: boolean) => void;
setExpanded: (nodeId: string, expanded: boolean) => void;
setPage: (nodeId: string, page: number) => void;
setSearchTerm: (nodeId: string, searchTerm?: string) => void;
setSelectedIds: (selectedNodeIds: string[]) => void;
setScrollTo: (nodeId: string, scrollTo: boolean) => void;
refreshChildren: (nodeId: string, forceLoading: boolean) => void;
}
- useElementTreeNode
Reads and controls a single element tree node by ID.
import { useElementTreeNode } from '@pimcore/studio-ui-bundle/components'
const useElementTreeNode: (nodeId: string) => NodeState & {
isExpanded: boolean;
setLoading: (loading: boolean) => void;
setFetching: (isFetching: boolean) => void;
setExpanded: (expanded: boolean) => void;
setPage: (page: number) => void;
setSearchTerm: (searchTerm?: string) => void;
setSelectedIds: (selectedNodeIds: string[]) => void;
setScrollTo: (scrollTo: boolean) => void;
getChildren: () => string[];
}
- useElementTreeRootNode
Fetches the root node of an element tree by element id. Pass showRoot: true to include the root node itself in the rendered tree.
import { useElementTreeRootNode } from '@pimcore/studio-ui-bundle/components'
interface UseElementTreeRootNodeResult {
rootNode?: TreeNode;
isLoading: boolean;
}
const useElementTreeRootNode: (id: number, showRoot: boolean) => UseElementTreeRootNodeResult;
- useNodeApiHook
Accesses the NodeApiHook from the nearest NodeApiHookProvider. Used to customize how tree node data is fetched.
import { useNodeApiHook } from '@pimcore/studio-ui-bundle/components'
interface INodeApiHookContext {
nodeApiHook: NodeApiHook;
}
const useNodeApiHook: () => INodeApiHookContext;
- useUploadModalContext
Accesses the upload modal context (must be inside an upload modal provider).
import { useUploadModalContext } from '@pimcore/studio-ui-bundle/components'
const useUploadModalContext: () => UploadContextProps
@pimcore/studio-ui-bundle/app
- useTranslation
Re-export of react-i18next's useTranslation. Use for accessing Pimcore i18n translations.
import { useTranslation } from '@pimcore/studio-ui-bundle/app'
@pimcore/studio-ui-bundle/modules/app
- useSettings
Returns the Pimcore system settings fetched from the API.
import { useSettings } from '@pimcore/studio-ui-bundle/modules/app'
const useSettings: () => SystemSettingsGetApiResponse
- useMainNav
Returns the registered main navigation items. Use together with MainNavRegistry to read or extend the top-level navigation.
import { useMainNav } from '@pimcore/studio-ui-bundle/modules/app'
interface IUseMainNavReturn {
navItems: IMainNavItem[];
}
const useMainNav: () => IUseMainNavReturn
@pimcore/studio-ui-bundle/modules/element
- useElementContext
Returns the current element's id and elementType from context. Must be inside an element editor.
import { useElementContext } from '@pimcore/studio-ui-bundle/modules/element'
const useElementContext: () => { id: number; elementType: ElementType }
- useOptionalElementContext
Same as useElementContext but returns null instead of throwing when no context is present.
import { useOptionalElementContext } from '@pimcore/studio-ui-bundle/modules/element'
const useOptionalElementContext: () => { id: number; elementType: ElementType } | null
- useElementApi
Low-level API for patching, fetching, and cloning elements by type.
import { useElementApi } from '@pimcore/studio-ui-bundle/modules/element'
const useElementApi: (elementType: ElementType, cacheKey?: string) => {
elementPatch: (args: ElementPatchArgs) => Promise<boolean>;
getElementById: (id: number) => Promise<AssetGetByIdApiResponse | DataObjectGetByIdApiResponse | undefined>;
elementClone: (args: ElementCloneArgs) => Promise<ElementCloneResponse>;
}
- useElementDraft
Reads the Redux draft state for any element. Combines properties, schedules, tabs, and change tracking.
import { useElementDraft } from '@pimcore/studio-ui-bundle/modules/element'
const useElementDraft: (id: number, elementType: ElementType) => {
element: IElementDraft | undefined;
editorType: ElementEditorType | undefined;
isLoading: boolean;
isError: boolean;
// + UsePropertiesDraftReturn, UseSchedulesDraftReturn, UseTabsDraftReturn,
// + UseModifiedObjectDataDraftReturn, UseDraftDataReturn, UseTrackableChangesDraftReturn, UsePublishedData
}
- useElementHelper
Utility for opening an element in a widget, mapping type strings, and executing save tasks.
import { useElementHelper } from '@pimcore/studio-ui-bundle/modules/element'
const useElementHelper: () => {
openElement: (props: OpenElementWidgetProps) => Promise<void>;
mapToElementType: (elementType: string, silent?: boolean) => ElementType | undefined;
executeElementTask: (elementType: ElementType, id: number, task: SaveTaskType, onFinish?: () => void) => void;
}
- useGlobalElementContext
Reads the global (cross-widget) element context.
import { useGlobalElementContext } from '@pimcore/studio-ui-bundle/modules/element'
const useGlobalElementContext: () => {
context: GlobalAssetContext | GlobalDataObjectContext | GlobalDocumentContext | undefined;
}
- useCacheUpdate
Invalidates or patches RTK Query cache entries for an element type.
import { useCacheUpdate } from '@pimcore/studio-ui-bundle/modules/element'
const useCacheUpdate: (elementType: ElementType, tags: ReadonlyArray<TagDescription<string>>) => {
update: (props: UpdateCacheProps) => void;
updateFieldValue: (id: number, field: string, value: any) => void;
}
- useElementSelector
Opens the element selector dialog programmatically.
import { useElementSelector } from '@pimcore/studio-ui-bundle/modules/element'
const useElementSelector: (props: UseElementSelectorProps) => { open: () => void }
- useDynamicTypeResolver
Resolves dynamic type registrations to their component renderers.
import { useDynamicTypeResolver } from '@pimcore/studio-ui-bundle/modules/element'
const useDynamicTypeResolver: () => {
getComponentRenderer: (props: typeProps) => IComponentRenderer;
hasType: (props: typeProps) => boolean;
getType: (dynamicTypeId: DynamicTypeAbstract['id']) => DynamicTypeAbstract | null;
}
- useTabManager
Returns the TabManager instance for the current element editor. Provides getTabs(), getTab(key), and register(tab) for reading or extending the editor's tab list.
import { useTabManager } from '@pimcore/studio-ui-bundle/modules/element'
const useTabManager: () => TabManager
- useFieldWidth
Returns the responsive field-width breakpoints (small, medium, large) from the nearest FieldWidthProvider. Used inside data-object field components to adapt their layout.
import { useFieldWidth } from '@pimcore/studio-ui-bundle/modules/element'
interface IFieldWidthContext {
small: number;
medium: number;
large: number;
}
const useFieldWidth: () => IFieldWidthContext
Action hooks (all take elementType: ElementType)
- useAddFolder
Opens a "create folder" dialog for a given parent and provides a tree context menu item and direct mutation for creating a folder under a given parent element.
import { useAddFolder } from '@pimcore/studio-ui-bundle/modules/element'
const useAddFolder: (elementType: ElementType) => {
addFolder: (parentId: number) => void;
addFolderTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
addFolderMutation: (parentId: number, value: string) => Promise<void>;
}
- useCopyPaste
Manages clipboard state (copy/cut) and provides paste, move, and all related tree and grid context menu items for element operations.
import { useCopyPaste } from '@pimcore/studio-ui-bundle/modules/element'
const useCopyPaste: (elementType: ElementType) => {
storedNode: StoreNode;
nodeTask: 'copy' | 'cut' | undefined;
copy: (node: TreeNodeProps) => void;
cut: (node: TreeNodeProps) => void;
paste: (parentId: number, cloneParameters?: CloneParameters, node?: StoreNode) => Promise<void>;
pasteCut: (parentId: number) => Promise<void>;
move: (props: MoveProps) => Promise<void>;
copyTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
copyContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
cutTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
cutContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
pasteTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
pasteCutContextMenuItem: (parentId: number) => ItemType;
}
- useDelete
Deletes an element with a confirmation prompt and provides tree, context, and grid menu items for deletion.
import { useDelete } from '@pimcore/studio-ui-bundle/modules/element'
const useDelete: (elementType: ElementType, cacheKey?: string) => {
deleteElement: (id: number, label: string, parentId?: number) => void;
deleteTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
deleteContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
deleteGridContextMenuItem: (row: any) => ItemType | undefined;
deleteMutation: (id: number, parentId?: number) => Promise<void>;
}
- useDeleteDraft
Discards the current unsaved draft for an element, resetting it to the last saved state.
import { useDeleteDraft } from '@pimcore/studio-ui-bundle/modules/element'
const useDeleteDraft: (elementType: ElementType) => {
deleteDraft: () => Promise<void>;
buttonText: string;
isLoading: boolean;
isError: boolean;
}
- useLocateInTree
Scrolls the element tree to a given element ID and provides a grid context menu item for the locate action.
import { useLocateInTree } from '@pimcore/studio-ui-bundle/modules/element'
const useLocateInTree: (elementType: ElementType) => {
locateInTree: (elementId: number, onFinished?: () => void) => void;
locateInTreeGridContextMenuItem: (row: any, onFinish?: () => void) => ItemType | undefined;
}
- useLock
Locks or unlocks an element (with optional propagation to children) and provides all related tree and context menu items.
import { useLock } from '@pimcore/studio-ui-bundle/modules/element'
const useLock: (elementType: ElementType) => {
lock: (id: number) => Promise<void>;
lockAndPropagate: (id: number) => Promise<void>;
unlock: (id: number) => Promise<void>;
unlockAndPropagate: (id: number) => Promise<void>;
lockTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
lockContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
lockAndPropagateTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
lockAndPropagateContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
unlockTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
unlockContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
unlockAndPropagateTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
unlockAndPropagateContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
isLockMenuHidden: (node: Element | TreeNodeProps) => boolean;
}
- usePublish
Publishes an element directly and provides a tree context menu item for the publish action.
import { usePublish } from '@pimcore/studio-ui-bundle/modules/element'
const usePublish: (elementType: ElementType) => {
publishTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
publishNode: (node: TreeNodeProps | Element) => void;
}
- useElementRefresh
Triggers a data reload for a specific element by ID, optionally scoped to the element tab view.
import { useElementRefresh } from '@pimcore/studio-ui-bundle/modules/element'
const useElementRefresh: (elementType: ElementType) => {
refreshElement: (id: number, inElementTab?: boolean) => void;
}
- useRefreshGrid
Reloads the element grid listing, optionally scoped to a specific parent folder.
import { useRefreshGrid } from '@pimcore/studio-ui-bundle/modules/element'
const useRefreshGrid: (elementType: ElementType) => {
refreshGrid: (parentId?: number) => Promise<void>;
}
- useRename
Opens an inline rename input for an element and provides tree, context, and grid menu items for the rename action.
import { useRename } from '@pimcore/studio-ui-bundle/modules/element'
const useRename: (elementType: ElementType, cacheKey?: string) => {
rename: (parentId: number, currentLabel: string) => void;
renameTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
renameContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
renameGridContextMenuItem: (row: any) => ItemType | undefined;
renameMutation: (parentId: number, value: string) => Promise<void>;
}
Draft hooks (low-level, used inside element editors)
- useDraftDataDraft
Low-level draft hook for storing arbitrary draft data payload for an element in Redux.
const useDraftDataDraft: (id: number, setDraftDataAction: ActionCreatorWithPayload<{ id: number; draftData: any }>) => {
setDraftData: (draftData: any) => void;
}
- usePropertiesDraft
Low-level draft hook for managing element properties (add, update, remove, replace all) in Redux.
import { usePropertiesDraft } from '@pimcore/studio-ui-bundle/modules/element'
interface UsePropertiesDraftReturn {
properties: undefined | DataProperty[];
updateProperty: (key: string, updatedProperty: DataProperty) => void;
addProperty: (property: DataProperty) => void;
removeProperty: (property: DataProperty) => void;
setProperties: (properties: DataProperty[]) => void;
}
const usePropertiesDraft: (
id: number,
draft: PropertiesDraft,
updatePropertyAction: ActionCreatorWithPayload<PropertyAction>,
addPropertyAction: ActionCreatorWithPayload<PropertyAction>,
removePropertyAction: ActionCreatorWithPayload<PropertyAction>,
setPropertiesAction: ActionCreatorWithPayload<PropertiesAction>
) => UsePropertiesDraftReturn
- useSchedulesDraft
Low-level draft hook for managing element schedules (add, update, remove, replace all, reset changes) in Redux.
import { useSchedulesDraft } from '@pimcore/studio-ui-bundle/modules/element'
interface UseSchedulesDraftReturn {
schedules: undefined | Schedule[];
updateSchedule: (schedule: Schedule) => void;
addSchedule: (schedule: Schedule) => void;
removeSchedule: (schedule: Schedule) => void;
setSchedules: (schedules: Schedule[]) => void;
resetSchedulesChanges: () => void;
}
const useSchedulesDraft: (
id: number,
draft: SchedulesDraft,
updateScheduleAction: ActionCreatorWithPayload<ScheduleAction>,
addScheduleAction: ActionCreatorWithPayload<ScheduleAction>,
removeScheduleAction: ActionCreatorWithPayload<ScheduleAction>,
setSchedulesAction: ActionCreatorWithPayload<SchedulesAction>,
resetSchedulesChangesAction: ActionCreatorWithPayload<number>
) => UseSchedulesDraftReturn
- useTabsDraft
Low-level draft hook for reading and setting the active tab of an element editor in Redux.
import { useTabsDraft } from '@pimcore/studio-ui-bundle/modules/element'
interface UseTabsDraftReturn extends TabsDraft {
setActiveTab: (tab: string) => void;
}
// TabsDraft: { activeTab: string | null }
const useTabsDraft: (
id: number,
draft: TabsDraft,
setActiveTabAction: ActionCreatorWithPayload<SetActiveTabAction>
) => UseTabsDraftReturn
- useTrackableChangesDraft
Low-level draft hook for tracking dirty state — clears change records or marks specific grid cells as modified in Redux.
import { useTrackableChangesDraft } from '@pimcore/studio-ui-bundle/modules/element'
interface UseTrackableChangesDraftReturn {
removeTrackedChanges: () => void;
setModifiedCells: (type: string, modifiedCells: ModifiedCells) => void;
}
const useTrackableChangesDraft: (
id: number,
resetChangesAction: ActionCreatorWithPayload<number>,
setModifiedCellsAction: ActionCreatorWithPayload<ModifiedCellsAction>
) => UseTrackableChangesDraftReturn
- usePublishedDraft
Low-level draft hook for toggling the published state of an element in Redux. Dispatch publishDraft() or unpublishDraft() to update the slice.
import { usePublishedDraft } from '@pimcore/studio-ui-bundle/modules/element'
interface UsePublishedData {
publishDraft: () => void;
unpublishDraft: () => void;
}
const usePublishedDraft: (
id: number,
publishDraftAction: ActionCreatorWithPayload<{ id: number }>,
unpublishDraftAction: ActionCreatorWithPayload<{ id: number }>
) => UsePublishedData
@pimcore/studio-ui-bundle/modules/data-object
- useDataObject
Returns the current data object ID from context.
import { useDataObject } from '@pimcore/studio-ui-bundle/modules/data-object'
const useDataObject: () => { id: number | undefined }
- useDataObjectDraft
Full draft state for a data object editor.
import { useDataObjectDraft } from '@pimcore/studio-ui-bundle/modules/data-object'
const useDataObjectDraft: (id: number) => {
isLoading: boolean;
isError: boolean;
dataObject: undefined | DataObjectDraftState;
editorType: ElementEditorType | undefined;
// + UsePropertiesDraftReturn, UseSchedulesDraftReturn, UseTabsDraftReturn,
// + UseModifiedObjectDataDraftReturn, UseDraftDataReturn, UseTrackableChangesDraftReturn, UsePublishedData
}
- useDataObjectHelper
Opens a data object in its widget or executes a save task.
import { useDataObjectHelper } from '@pimcore/studio-ui-bundle/modules/data-object'
const useDataObjectHelper: () => {
openDataObject: (props: OpenDataObjectWidgetProps) => Promise<void>;
executeDataObjectTask: (id: number, task: SaveTaskType, onFinish?: () => void) => Promise<void>;
}
- useGlobalDataObjectContext
Reads and sets the global cross-widget data object context (the currently "focused" data object ID shared across panels).
import { useGlobalDataObjectContext } from '@pimcore/studio-ui-bundle/modules/data-object'
const useGlobalDataObjectContext: () => {
context: { type: 'data-object'; config: { id: number } } | undefined;
setContext: (config: { id: number }) => void;
removeContext: () => void;
}
- useCustomLayouts
Fetches available custom layouts for a data object.
import { useCustomLayouts } from '@pimcore/studio-ui-bundle/modules/data-object'
const useCustomLayouts: (id: number) => {
layouts: Layout[] | undefined;
getDefaultLayoutId: (currentLayout?: string | null) => string | null;
isLoading: boolean;
}
- useQuantityValueUnits
Resolves quantity value units for select dropdowns and unit conversion.
import { useQuantityValueUnits } from '@pimcore/studio-ui-bundle/modules/data-object'
const useQuantityValueUnits: () => {
getSelectOptions: (validUnits?: string[]) => DefaultOptionType[];
convertValue: (fromUnitId: string, toUnitId: string, value: number) => Promise<number | null>;
getAbbreviation: (unitId: string) => string;
}
- useSave
Saves a data object draft. Pass SaveTaskType to control the operation.
import { useSave } from '@pimcore/studio-ui-bundle/modules/data-object'
const useSave: (useDraftData?: boolean) => {
save: (editableData: Record<string, any>, task?: SaveTaskType, onFinish?: () => void) => Promise<void>;
isLoading: boolean;
isSuccess: boolean;
isError: boolean;
error: FetchBaseQueryError | SerializedError | undefined;
}
enum SaveTaskType {
Version = "version",
AutoSave = "autoSave",
Publish = "publish",
Save = "save",
Unpublish = "unpublish"
}
- useAddObject
Provides a tree context menu item for creating a new data object child under the selected node.
import { useAddObject } from '@pimcore/studio-ui-bundle/modules/data-object'
const useAddObject: () => {
addObjectTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
}
- useLanguageSelection
Accesses the current language selection context inside a localized data object editor.
import { useLanguageSelection } from '@pimcore/studio-ui-bundle/modules/data-object'
const useLanguageSelection: () => UseLanguageSelectionReturn
Draft hooks (low-level, used inside data object editors)
- useModifiedObjectDataDraft
Low-level draft hook that marks the data object's object-data fields as modified in Redux, triggering dirty-state detection.
import { useModifiedObjectDataDraft } from '@pimcore/studio-ui-bundle/modules/data-object'
interface UseModifiedObjectDataDraftReturn {
markObjectDataAsModified: () => void;
}
const useModifiedObjectDataDraft: (
id: number,
draft: ModifiedObjectDataDraft,
markObjectDataAsModifiedAction: ActionCreatorWithPayload<number>
) => UseModifiedObjectDataDraftReturn
@pimcore/studio-ui-bundle/modules/asset
- useAsset
Returns the current asset ID from context.
import { useAsset } from '@pimcore/studio-ui-bundle/modules/asset'
const useAsset: () => { id: number }
- useAssetDraft
Full draft state for an asset editor.
import { useAssetDraft } from '@pimcore/studio-ui-bundle/modules/asset'
const useAssetDraft: (id: number) => {
isLoading: boolean;
isError: boolean;
asset: undefined | AssetDraftState;
editorType: ElementEditorType | undefined;
// + UseCustomMetadataDraftReturn, UseCustomSettingsDraftReturn, UsePropertiesDraftReturn,
// + UseSchedulesDraftReturn, UseTrackableChangesDraftReturn, UseTabsDraftReturn,
// + UseTextDataDraftReturn, UseImageSettingsDraftReturn
}
- useAssetHelper
Opens an asset in its editor widget by passing an OpenAssetWidgetProps config.
import { useAssetHelper } from '@pimcore/studio-ui-bundle/modules/asset'
const useAssetHelper: () => {
openAsset: (props: OpenAssetWidgetProps) => void;
}
- useGlobalAssetContext
Reads and sets the global cross-widget asset context (the currently "focused" asset ID shared across panels).
import { useGlobalAssetContext } from '@pimcore/studio-ui-bundle/modules/asset'
const useGlobalAssetContext: () => {
context: { type: 'asset'; config: { id: number } } | undefined;
setContext: (config: { id: number }) => void;
removeContext: () => void;
}
- useClearThumbnails
Provides context menu items for clearing cached image, video, or PDF thumbnails for an asset.
import { useClearThumbnails } from '@pimcore/studio-ui-bundle/modules/asset'
const useClearThumbnails: () => {
clearImageThumbnailContextMenuItem: (node: Asset, onFinish?: () => void) => ItemType;
clearVideoThumbnailContextMenuItem: (node: Asset, onFinish?: () => void) => ItemType;
clearPdfThumbnailContextMenuItem: (node: Asset, onFinish?: () => void) => ItemType;
}
- useDownload
Triggers a direct file download for an asset and provides tree, context, and grid menu items for the download action.
import { useDownload } from '@pimcore/studio-ui-bundle/modules/asset'
const useDownload: () => {
download: (id: string, label?: string) => void;
downloadContextMenuItem: (node: Asset, onFinish?: () => void) => ItemType;
downloadTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
downloadGridContextMenuItem: (row: any) => ItemType | undefined;
}
- useZipDownload
Creates a zip archive download for a folder or an explicit list of assets and provides the related context menu items.
import { useZipDownload } from '@pimcore/studio-ui-bundle/modules/asset'
const useZipDownload: (props: { type: 'folder' | 'asset-list' }) => {
createZipDownload: CreateFolderZipDownload | CreateAssetListZipDownload;
createZipDownloadContextMenuItem: (node: Element, onFinish?: () => void) => ItemType;
createZipDownloadTreeContextMenuItem: (node: TreeNodeProps) => ItemType;
}
Draft hooks (low-level, used inside asset editors)
- useCustomMetadataDraft
Low-level draft hook for managing the custom metadata list of an asset in Redux.
import { useCustomMetadataDraft } from '@pimcore/studio-ui-bundle/modules/asset'
interface UseCustomMetadataDraftReturn {
customMetadata: undefined | CustomMetadata[];
updateCustomMetadata: (customMetadata: CustomMetadata) => void;
addCustomMetadata: (customMetadata: CustomMetadata) => void;
removeCustomMetadata: (customMetadata: CustomMetadata) => void;
updateAllCustomMetadata: (customMetadata: CustomMetadata[]) => void;
setCustomMetadata: (customMetadata: CustomMetadata[]) => void;
}
const useCustomMetadataDraft: (
id: number,
draft: CustomMetadataDraft,
updateCustomMetadataAction: ActionCreatorWithPayload<CustomMetadataAction>,
addCustomMetadataAction: ActionCreatorWithPayload<CustomMetadataAction>,
removeCustomMetadataAction: ActionCreatorWithPayload<CustomMetadataAction>,
setCustomMetadataAction: ActionCreatorWithPayload<CustomMetadataArrayAction>,
updateAllCustomMetadataAction: ActionCreatorWithPayload<CustomMetadataArrayAction>
) => UseCustomMetadataDraftReturn
- useImageSettingsDraft
Low-level draft hook for reading and mutating image settings (focal point, cropping, etc.) for an asset in Redux.
import { useImageSettingsDraft } from '@pimcore/studio-ui-bundle/modules/asset'
interface UseImageSettingsDraftReturn {
imageSettings: undefined | ImageData;
addImageSettings: (settings: ImageData) => void;
removeImageSetting: (setting: keyof ImageData) => void;
updateImageSetting: (setting: keyof ImageData, value: ImageData[keyof ImageData]) => void;
}
const useImageSettingsDraft: (
id: number,
draft: ImageSettingsDraft,
addSettingsAction: ActionCreatorWithPayload<ImageSettingsAction>,
removeSettingAction: ActionCreatorWithPayload<ImageSettingAction>,
updateSettingAction: ActionCreatorWithPayload<UpdateImageSettingAction>
) => UseImageSettingsDraftReturn
@pimcore/studio-ui-bundle/modules/user
- useGlobalUserContext
Reads and sets the global cross-widget user context (the currently "focused" user ID shared across panels).
import { useGlobalUserContext } from '@pimcore/studio-ui-bundle/modules/user'
const useGlobalUserContext: () => {
context: { type: 'user'; config: { id: number } } | undefined;
setContext: (config: { id: number }) => void;
removeContext: () => void;
}
- useUserManagementDraft
Reads and mutates the local Redux draft state for a user editor, including changing field values and key bindings.
import { useUserManagementDraft } from '@pimcore/studio-ui-bundle/modules/user'
const useUserManagementDraft: (id: number) => {
isLoading: boolean;
isError: boolean;
user: undefined | UserDraftState;
removeUserFromState: () => void;
changeUserInState: (changedValues: any) => void;
updateUserKeyBinding: (name: string, code: object) => void;
reloadUser: () => void;
}
- useUserManagementHelper
High-level helper for user management operations: opening/closing user editors, CRUD actions (add, remove, clone, update, move), avatar upload, and user search.
import { useUserManagementHelper } from '@pimcore/studio-ui-bundle/modules/user'
const useUserManagementHelper: () => {
openUser: (id: number) => void;
closeUser: (id: number) => void;
addNewUser: (props: AddItemArgs) => Promise<{ data: UserCreateApiResponse; error: any }>;
removeUser: (props: UserDeleteByIdApiArg) => Promise<{ data: UserDeleteByIdApiResponse; error: any }>;
cloneUser: (props: { id: number; name: string }) => Promise<{ data: UserCloneByIdApiResponse; error: any }>;
updateUserById: (props: { id: number; user: User2 | User }) => Promise<{ data: UserUpdateByIdApiResponse; error: any }>;
moveUserById: (props: { id: number; parentId: number }) => Promise<{ data: UserUpdateByIdApiResponse; error: any }>;
fetchUserList: () => Promise<UserGetCollectionApiResponse>;
searchUserByText: (query: string) => Promise<PimcoreStudioApiUserSearchApiResponse>;
uploadUserAvatar: (props: { id: number; file: File }) => Promise<{ data: UserUploadImageApiResponse; error: any }>;
activeId: number;
getAllIds: number[];
// ... more methods
}
- useRoleDraft
Reads and mutates the local Redux draft state for a role editor, including changing field values and reloading from the API.
import { useRoleDraft } from '@pimcore/studio-ui-bundle/modules/user'
const useRoleDraft: (id: number) => {
isLoading: boolean;
isError: boolean;
role: undefined | RoleDraftState;
removeRoleFromState: () => void;
changeRoleInState: (changedValues: any) => void;
reloadRole: () => void;
}
- useRoleHelper
High-level helper for role management operations: opening/closing role editors and CRUD actions (add, remove, clone, update, move).
import { useRoleHelper } from '@pimcore/studio-ui-bundle/modules/user'
const useRoleHelper: () => {
openRole: (id: number) => void;
closeRole: (id: number) => void;
addNewRole: (props: IAddRoleArgs) => Promise<{ data: RoleCreateApiResponse; error: any }>;
removeRole: (props: RoleDeleteByIdApiArg) => Promise<{ data: RoleDeleteByIdApiResponse; error: any }>;
cloneRole: (props: { id: number; name: string }) => Promise<{ data: RoleCloneByIdApiResponse; error: any }>;
updateRoleById: (props: { id: number; item: DetailedUserRole }) => Promise<{ data: RoleUpdateByIdApiResponse; error: any }>;
moveRoleById: (props: { id: number; parentId: number }) => Promise<{ data: RoleUpdateByIdApiResponse; error: any }>;
getRoleCollection: () => Promise<RoleGetCollectionApiResponse>;
activeId: number;
getAllIds: number[];
}
@pimcore/studio-ui-bundle/modules/widget-manager
- useWidgetManager
Controls the FlexLayout widget panels. Use openMainWidget / openBottomWidget / openLeftWidget / openRightWidget to open a registered widget by passing a WidgetManagerTabConfig. Use switchToWidget / closeWidget by tab id, and isMainWidgetOpen to check visibility.
import { useWidgetManager } from '@pimcore/studio-ui-bundle/modules/widget-manager'
const useWidgetManager: () => {
openMainWidget: (tabConfig: WidgetManagerTabConfig) => void;
openBottomWidget: (tabConfig: WidgetManagerTabConfig) => void;
openLeftWidget: (tabConfig: WidgetManagerTabConfig) => void;
openRightWidget: (tabConfig: WidgetManagerTabConfig) => void;
switchToWidget: (id: string) => void;
closeWidget: (id: string) => void;
isMainWidgetOpen: (id: string) => boolean;
getOpenedMainWidget: () => TabNode | undefined;
}
@pimcore/studio-ui-bundle/utils
- useClickOutside
Fires handler when a click occurs outside the given ref. Optional selectors CSS string to ignore specific targets.
import { useClickOutside } from '@pimcore/studio-ui-bundle/utils'
const useClickOutside: (
ref: MutableRefObject<any>,
handler: (event: MouseEvent) => void,
selectors?: string
) => void
- useCssContainer
Generates CSS container query style definitions.
import { useCssContainer } from '@pimcore/studio-ui-bundle/utils'
const useCssContainer: ({ name, type }: { name: string; type?: string }) => {
styleDefinition: ReturnType<typeof useCssContainerStyles>;
}
- usePrevious
Returns the previous render's value of any variable.
import { usePrevious } from '@pimcore/studio-ui-bundle/utils'
const usePrevious: <T>(value: T) => T | undefined
- useServerSideEvent
Subscribes to Pimcore SSE (Server-Sent Events) topics. Returns open/close controls.
import { useServerSideEvent } from '@pimcore/studio-ui-bundle/utils'
const useServerSideEvent: (props: {
topics: NonEmptyArray<string>;
messageHandler?: (event: MessageEvent) => void;
openHandler?: () => void;
}) => {
open: () => void;
close: () => void;
}
- useElementResize
Returns the current pixel width of a div ref, updated on resize.
import { useElementResize } from '@pimcore/studio-ui-bundle/utils'
const useElementResize: (ref: RefObject<HTMLDivElement>) => number
- useElementVisible
Returns true when the element is visible in the viewport (uses IntersectionObserver).
import { useElementVisible } from '@pimcore/studio-ui-bundle/utils'
const useElementVisible: (
ref: RefObject<HTMLElement>,
continueObserving?: boolean,
disable?: boolean
) => boolean
Conclusion
Pimcore Studio introduces a more structured approach to extending the platform.
By working with SDK hooks instead of modifying internal implementations, you reduce dependency on underlying UI logic and avoid the fragility that often came with earlier customization methods. Extensions become easier to maintain, easier to understand, and more predictable across platform updates.
This shift changes not only how plugins are built, but also how teams approach long-term Pimcore development.
In more complex scenarios, such as building custom editor interfaces or integrating external systems, implementation often requires deeper platform knowledge and experience. In these cases, working with experienced Pimcore developers can help ensure that extensions are designed in a way that remains stable as the platform evolves.