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:

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.).

useMessage
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.

useNotification
import { useNotification } from '@pimcore/studio-ui-bundle/components' 
 
const useNotification: () => readonly [NotificationInstance] 
  • useModal

Provides controlled modal state with render helper.

useModal
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).

useAlertModal
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.

useFormModal
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'

useElementTree
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'

useElementTreeNode
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.

useElementTreeRootNode
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.

useNodeApiHook
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). 

useUploadModalContext
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.

useTranslation
import { useTranslation } from '@pimcore/studio-ui-bundle/app'  

@pimcore/studio-ui-bundle/modules/app

  • useSettings

Returns the Pimcore system settings fetched from the API.

useSettings
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.

useMainNav
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.

useElementContext
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.

useOptionalElementContext
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.

useElementApi
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. 

useElementDraft
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.

useElementHelper
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.

useGlobalElementContext
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.

useCacheUpdate
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.

useElementSelector
import { useElementSelector } from '@pimcore/studio-ui-bundle/modules/element' 
 
const useElementSelector: (props: UseElementSelectorProps) => { open: () => void }
  • useDynamicTypeResolver

Resolves dynamic type registrations to their component renderers.

useDynamicTypeResolver
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.

useTabManager
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.

useFieldWidth
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.

useAddFolder
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.

useCopyPaste
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.

useDelete
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.

useDeleteDraft
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.

useLocateInTree
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.

useLock
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.

usePublish
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.

useElementRefresh
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.

useRefreshGrid
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.

useRename
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.

useDraftDataDraft
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.

usePropertiesDraft
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.

useSchedulesDraft
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.

useTabsDraft
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.

useTrackableChangesDraft
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.

usePublishedDraft
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.

useDataObject
import { useDataObject } from '@pimcore/studio-ui-bundle/modules/data-object' 
 
const useDataObject: () => { id: number | undefined } 
  • useDataObjectDraft

Full draft state for a data object editor.

useDataObjectDraft
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.

useDataObjectHelper
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).

useGlobalDataObjectContext
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.

useCustomLayouts
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.

useQuantityValueUnits
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.

useSave
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.

useAddObject
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.

useLanguageSelection
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.

useModifiedObjectDataDraft
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.

useAsset
import { useAsset } from '@pimcore/studio-ui-bundle/modules/asset' 
 
const useAsset: () => { id: number } 
  • useAssetDraft

Full draft state for an asset editor.

useAssetDraft
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.

useAssetHelper
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).

useGlobalAssetContext
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.

useClearThumbnails
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.

useDownload
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.

useZipDownload
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.

useCustomMetadataDraft
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.

useImageSettingsDraft
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).

useGlobalUserContext
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.

useUserManagementDraft
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.

useUserManagementHelper
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.

useRoleDraft
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).

useRoleHelper
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.

useWidgetManager
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.

useClickOutside
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.

useCssContainer
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.

usePrevious
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.

useServerSideEvent
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.

useElementResize
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).

useElementVisible
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.

Looking for Exponential Growth? Let’s Get Started.
Explore next

Pimcore Whitepapers

Our Pimcore knowledge in your hands. Read and download our free whitepapers.

Discover more