Plugin SDK > Outlets

Outlets

Through plugins, it's possible to customize various areas of the DatoCMS interface. We call these customizable areas "outlets".

Outlets are essentially iframes where plugin developers can render custom content, providing enhanced functionality and user experiences within the DatoCMS ecosystem.

Outlets offer the ability to:

  • Access information related to records, projects, or logged-in users

  • Make calls to DatoCMS to produce various effects and interact with the main application (e.g., changing values, navigating, triggering notifications, opening modals)

  • Customize the user interface to fit specific workflow needs

If you prefer, a form outlet can also be completely hidden from the interface (setting his height to zero), and work under the cover to tweak the default behaviour of DatoCMS.

Types of Outlets

DatoCMS allows you to configure outlets in various areas of the interface.

Record Form Outlets

Record form outlets allow you to add custom areas above the record editing form:

Implementing a Record Form Outlet

The first step is to implement the itemFormOutlets hook, to declare our intent to add the outlet to the form:

import { connect, ItemFormOutletsCtx } from 'datocms-plugin-sdk';
connect({
itemFormOutlets(model, ctx: ItemFormOutletsCtx) {
return [
{
id: 'myOutlet',
initialHeight: 100,
},
];
},
});

The initialHeight property sets the initial height of the frame, while the plugin itself is loading. It can also be useful to completely hide the outlet, by passing the value zero to it.

The code above will add the outlet to the form of every record in our project, but you can also add some settings to the plugin to ie. let the final user pick only some specific models:

itemFormOutlets(model, ctx: ItemFormOutletsCtx) {
const { modelApiKeys } = ctx.plugin.attributes.parameters;
if (!modelApiKeys.includes(model.attributes.api_key)) {
// Don't add the outlet!
return [];
}
// Add the outlet!
}

The final step is to actually render the outlet itself by implementing the renderItemFormOutlet hook.

Inside of this hook we can initialize React and render a custom component, 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, RenderItemFormOutletCtx, ItemFormOutletsCtx } from 'datocms-plugin-sdk';
connect({
itemFormOutlets(model, ctx: ItemFormOutletsCtx) { ... },
renderItemFormOutlet(
outletId,
ctx: RenderItemFormOutletCtx,
) {
ReactDOM.render(
<React.StrictMode>
<MyCustomOutlet ctx={ctx} />
</React.StrictMode>,
document.getElementById('root'),
);
},
});

A plugin might render different types of form outlets, so we can use the outletId 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';
function MyCustomOutlet({ ctx }) {
return (
<Canvas ctx={ctx}>
Hello from the record form outlet!
</Canvas>
);
}
Always use the canvas!

If you want to render something inside the outlet, 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.

If you want the outlet to be hidden from the interface, just return null and set an initialHeight: 0 in the itemFormOutlets hook.

Record Collection Outlets

Record collection outlets allow you to add custom areas to the page that displays a collection of records for a specific model.

The implementation is exactly the same as the one we just saw for the Record Form Outlets. The only thing that changes is the hooks to be used:

Here's a full example:

import React from 'react';
import ReactDOM from 'react-dom';
import { connect, ItemCollectionOutletsCtx, RenderItemCollectionOutletCtx } from 'datocms-plugin-sdk';
import { Canvas, Button } from 'datocms-react-ui';
connect({
itemCollectionOutlets(model, ctx: ItemCollectionOutletsCtx) {
// Optional: Add conditions to show the outlet only for specific models
const { modelApiKeys } = ctx.plugin.attributes.parameters;
if (!modelApiKeys.includes(model.attributes.api_key)) {
return [];
}
return [
{
id: 'myCollectionOutlet',
initialHeight: 100,
},
];
},
renderItemCollectionOutlet(outletId, ctx: RenderItemCollectionOutletCtx) {
render(<MyCustomCollectionOutlet ctx={ctx} />);
},
});
function MyCustomCollectionOutlet({ ctx }) {
return (
<Canvas ctx={ctx}>
<h3>Custom Collection Outlet</h3>
<p>This outlet appears above the record listing for {ctx.itemType.attributes.name}.</p>
</Canvas>
);
}

Function Reference

renderItemFormOutlet()

Context object

The following properties and methods are available in the ctx argument:

renderItemCollectionOutlet()

Context object

The following properties and methods are available in the ctx argument:

itemFormOutlets()

Return value

The function must return ItemFormOutlet[].

Context object

The following properties and methods are available in the ctx argument:

itemCollectionOutlets()

Return value

The function must return ItemCollectionOutlet[].

Context object

The following properties and methods are available in the ctx argument: