Plugin SDK > Sidebar panels

    Sidebar panels

    Within the form for editing a record, it can be convenient to have some contextual information to keep an eye on while you are writing, without having to keep several tabs open or interrupt the flow.

    Through plugins it is possible to add a series of additional and fully customisable panels to the sidebar:

    A sidebar panel is nothing more than an iframe, inside of which the plugin developer can render what they prefer, while also having the possibility to:

    • access a series of information relating to the record that's being edited, the project in which the plugin is installed or the logged-in user;

    • make calls to DatoCMS to produce various effects and interact with the main application (changing form values, navigating to other pages, triggering notifications, opening modals, etc.);

    Implementing a simple sidebar panel

    Let's say we want to create a sidebar panel that will show a link pointing to the website page related to the record we're editing. The first step is to implement the itemFormSidebarPanels hook, to declare our intent to add the panel to the sidebar:

    import { connect, IntentCtx } from 'datocms-plugin-sdk';
    connect({
    itemFormSidebarPanels(model: ModelBlock, ctx: IntentCtx) {
    return [
    {
    id: 'goToWebsite',
    label: 'Go to website',
    startOpen: true,
    },
    ];
    },
    });

    The code above will add a panel to every record in our project... but maybe not every record in DatoCMS has a specific page in the final website, right?

    It might be better to add some settings to our plugin to let the final user declare the set of models that have permalinks, and the relative URL structure enforced on the frontend:

    itemFormSidebarPanels(model: ModelBlock, ctx: IntentCtx) {
    const { permalinksByModel } = ctx.plugin.attributes.parameters;
    // Assuming we're saving user preferences in this format:
    // {
    // 'blog_post': '/blog/:slug',
    // 'author': '/author/:slug',
    // ...
    // }
    }
    if (!permalinksByModel[model.attributes.api_key]) {
    // Don't add the panel!
    return [];
    }
    // Add the panel!
    }

    Rendering the panel

    The final step is to actually render the panel itself by implementing the renderItemFormSidebarPanel hook.

    Inside of this hook we initialize React and render a custom component called GoToWebsiteItemFormSidebarPanel, passing down as a prop the second ctx argument, which provides a series of information and methods for interacting with the main application:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { connect, RenderItemFormSidebarPanelCtx } from 'datocms-plugin-sdk';
    connect({
    renderItemFormSidebarPanel(
    sidebarPanelId,
    ctx: RenderItemFormSidebarPanelCtx,
    ) {
    ReactDOM.render(
    <React.StrictMode>
    <GoToWebsiteItemFormSidebarPanel ctx={ctx} />
    </React.StrictMode>,
    document.getElementById('root'),
    );
    },
    });

    A plugin might render different panels, so we can use the sidebarPanelId argument to know which one we are requested to render, and write a specific React component for each of them.

    import { Canvas } from 'datocms-react-ui';
    type PropTypes = {
    ctx: RenderItemFormSidebarPanelCtx;
    };
    function GoToWebsiteItemFormSidebarPanel({ ctx }: PropTypes) {
    return (
    <Canvas ctx={ctx}>
    Hello from the sidebar!
    </Canvas>
    );
    }
    Always use the canvas!

    It is important to wrap the content inside the Canvas component, so that the iframe will continuously auto-adjust its size based on the content we're rendering, and to give our app the look and feel of the DatoCMS web app.

    All we need to do now is to actually render the link to the website, reading from ctx.formValues the slug value and generating the final frontend URL:

    import { ButtonLink } from 'datocms-react-ui';
    function GoToWebsiteItemFormSidebarPanel({ ctx }: PropTypes) {
    if (ctx.itemStatus === 'new') {
    // we're in a record that still has not been persisted
    return <div>Please save the record first!</div>;
    }
    const { permalinksByModel } = ctx.plugin.attributes.parameters;
    const permalinkStructure = permalinksByModel[ctx.itemType.attributes.api_key];
    const url = permalinkStructure.replace(':slug', ctx.formValues.slug);
    return (
    <Canvas ctx={ctx}>
    <ButtonLink href={url} fullWidth>
    View it on the website!
    </ButtonLink>
    </Canvas>
    );
    }

    itemFormSidebarPanels

    Use this function to declare new sidebar panels to be shown when the user edits records of a particular model.

    Return value

    The function must return an array of objects with the following structure:

    Properties available in context

    The following information and methods are available:

    renderItemFormSidebarPanel

    This function will be called when the plugin needs to render a sidebar panel (see the itemFormSidebarPanels function).

    Properties available in context

    The following information and methods are available:

    Methods available in context

    The following information and methods are available: