Skip to main content
Developer Jahia 8.2

How do I add a custom action to the jContent menus, and can I override the Preview button?

Question

How do I add a custom action to the jContent menus, and can I override the Preview button?

Answer

A module registers a callback on jahiaApp-init, then registers its actions inside it:

import {registry} from '@jahia/ui-extender';
import register from './MyModule/register';

export default function () {
    registry.add('callback', 'myModule', {
        targets: ['jahiaApp-init:50'],
        callback: register
    });
}

The priority matters. jContent registers at jahiaApp-init:1, so a module must use a higher number to see or override jContent's own actions. Shipped modules use 50.

Target names

TargetWhere it appears
contentItemActionsthe three-dot (kebab) menu on each row
contentItemContextActionsright-click menu on each row
visibleContentItemActionsthe always-visible row icons, including the eye
headerPrimaryActionsmain header buttons
selectedContentActionsheader actions for a multi-row selection (gets paths)
accordionContentActionsleft tree context menu
browseControlBarkebab menu for the current node in the header

Do not use contentActions. It has been deprecated since jContent 3.2.0 and in current source the key is literally written '--contentActions' - the -- prefix means no action is assigned to it any more. Code targeting it does nothing.

To confirm a target name yourself rather than trusting a list, inspect the page: jContent renders data-registry-key and data-registry-target attributes (Jahia 8.1.6 and later).

An action that opens the render URL

This is the common case - a menu entry that opens /cms/render for the selected node.

Do not build the URL by hand. There is a server-side GraphQL field that does it properly, respecting vanity URLs and URL rewriting:

{
  jcr {
    nodeByPath(path: "/sites/digitall/home") {
      renderUrl(workspace: EDIT, language: "en", findDisplayable: true)
    }
  }
}

Run on 8.2.3.2 that returns:

/cms/render/default/en/sites/digitall/home.html

A hand-assembled string gives you the raw path and silently ignores any vanity URL the page has.

The action itself, modelled on jContent's own openInRepositoryExplorer:

export const OpenRenderActionComponent = ({path, render: Render, loading: Loading, ...others}) => {
    const language = useSelector(state => state.language);
    const res = useQuery(MY_RENDER_URL_QUERY, {variables: {path, language, workspace: 'EDIT'}, skip: !path});

    if (res.loading && Loading) { return <Loading {...others}/>; }
    const node = res?.data?.jcr?.result;
    if (!node) { return <Render {...others} isVisible={false}/>; }

    return (
        <Render {...others}
                isVisible
                enabled
                onClick={() => window.open(node.renderUrl, '_blank')}/>
    );
};

registered as:

registry.add('action', 'openRender', {
    targets: ['contentItemActions:10'],
    buttonIcon: <Visibility/>,
    buttonLabel: 'myModule:label.openRender',
    component: OpenRenderActionComponent
});

Two things that trip people up:

  • Your component must not render a button. It renders the injected Render component and passes isVisible, enabled and onClick to it.
  • The node path arrives as the path prop - a string. For multi-selection targets you get paths, an array, instead. There is no uuid prop; get it from a query or from useNodeChecks({path}, ...). A node prop is sometimes prefetched but is not always supplied, so do not depend on it.

Overriding the Preview button

registry.add throws if the key already exists. Use registry.addOrReplace, and spread the existing descriptor so you keep the parts you are not changing - this is what jExperience does in production:

registry.addOrReplace('action', 'edit', {
    ...registry.get('action', 'edit'),
    hideOnNodeTypes: [...]
});

But first: there are two Preview buttons, both with an eye icon and both labelled "Preview".

KeyWhat it does
Eye icon on each rowpreviewopens the in-app preview side panel
Preview button in the headeropenInPreviewalready opens the render URL in a new tab

So if what you want is "Preview should open the rendered page in a new tab", the header button already does that - check it before writing code.

If you do override preview, be aware it changes the action everywhere it appears, not just the row icon: it is also in the kebab and context menus. Adding a new action is usually cleaner than overriding that one.

"Edit in a new tab" from the ordering section

Not available. The ordering UI renders four hardcoded move buttons and nothing else, and there is no registry target in that part of the tree - so it cannot be contributed by a module either.

The feature exists only as an open, unmerged pull request against jContent (#2325). Until that lands there is no supported way to do it short of forking.


This article was drafted with AI assistance, then reviewed and curated by Jahia Customer Support engineers before publication.