NextJS/JSS Edit Frames Before JSS v21.1.0

> It is possible. We have the technology.
Cover Image for NextJS/JSS Edit Frames Before JSS v21.1.0

Overview

I wanted to implement edit Frames on a NextJS/TS/JSS v20.1.3 site. I was disappointed to find out that official support for edit frames was only added in v21.1.0, so I went out looking for other options.

Why Edit Frames?

Edit frames are a useful tool for content authors to edit arbitrary fields on arbitrary items via arbitrarily placed clickable elements on a page. One example would be if you wanted a way for a user to edit a background image on a section. You might render an absolutely positioned clickable icon that would allow the background image field to be edited. The possibilities are endless.

The Implementation

I was inspired by this SSE post about possible solutions: https://sitecore.stackexchange.com/questions/24307/edit-frame-with-sitecore-jss.

One of the answers points to a custom implementation of edit frames that someone wrote ~3.5 years before Sitecore added official support for it 👀: https://github.com/Sitecore/jss/pull/290. I refactored / modernized the code to work with strict TypeScript and the latest React patterns.

The Code


_84
import React from 'react';
_84
import { useSitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs';
_84
_84
interface FieldEditFrameProps {
_84
itemId?: string;
_84
fields?: string[];
_84
header?: string;
_84
icon?: string;
_84
disabledIcon?: string;
_84
tooltip?: string;
_84
command?: string;
_84
commandDisplayName?: string;
_84
databaseName?: string;
_84
language?: string;
_84
hideIfNotPageEditing?: boolean;
_84
}
_84
_84
const FieldEditFrame: React.FC<FieldEditFrameProps> = ({
_84
itemId = '',
_84
fields = [],
_84
header = 'Edit Fields',
_84
icon = '/temp/iconcache/people/16x16/cubes_blue.png',
_84
disabledIcon = '/temp/cubes_blue_disabled16x16.png',
_84
tooltip,
_84
command = '{70C4EED5-D4CD-4D7D-9763-80C42504F5E7}',
_84
commandDisplayName,
_84
databaseName,
_84
language,
_84
hideIfNotPageEditing,
_84
children,
_84
}) => {
_84
const { sitecoreContext } = useSitecoreContext();
_84
const { pageEditing, language: sitecoreLanguage, route } = sitecoreContext;
_84
const shouldRender = pageEditing && itemId && fields && fields.length;
_84
_84
if (!shouldRender && hideIfNotPageEditing) {
_84
return null;
_84
}
_84
_84
if (!itemId || !fields) {
_84
return null;
_84
}
_84
_84
// TODO: handle route undefined
_84
const contextItemUri = `sitecore://${databaseName || route?.databaseName}/${itemId}?lang=${
_84
language || sitecoreLanguage
_84
}`;
_84
_84
const clickCommandAction = `webedit:fieldeditor(command=${command},fields=${fields.join(
_84
'|'
_84
)},id=${itemId})`;
_84
_84
const clickCommand = {
_84
click: `javascript:Sitecore.PageModes.PageEditor.postRequest('${clickCommandAction}',null,false)`,
_84
header: header,
_84
icon: icon,
_84
disabledIcon: disabledIcon,
_84
isDivider: false,
_84
tooltip: tooltip || `Edit the following fields: ${fields.join(', ')}`,
_84
type: null,
_84
};
_84
_84
const commandData = {
_84
commands: [clickCommand],
_84
contextItemUri: contextItemUri,
_84
custom: {},
_84
displayName: commandDisplayName || 'Edit Properties',
_84
expandedDisplayName: '',
_84
};
_84
_84
const divAttrs = {
_84
sc_item: contextItemUri,
_84
'sc-part-of': 'editframe',
_84
};
_84
_84
return (
_84
<div className="scLooseFrameZone scEnabledChrome" {...divAttrs}>
_84
<span className="scChromeData">{JSON.stringify(commandData)}</span>
_84
{children}
_84
</div>
_84
);
_84
};
_84
_84
export default FieldEditFrame;

Example Implementation


_15
import FieldEditFrame from './../../utils/FieldEditFrame';
_15
_15
// other code
_15
_15
return (
_15
<>
_15
<FieldEditFrame
_15
// of course, its better not to hardcode these values
_15
itemId="{FEA43559-D12F-47C9-911C-8170B7FAEFA4}"
_15
fields={['Alert Label']}
_15
>
_15
<h2>Goo Goo Ga Ga</h2>
_15
</FieldEditFrame>
_15
</>
_15
);

Now the element is clickable: Edit fields popup

And clicking the blocks icon opens the field editor window: Field editor window

Further Steps

Be sure to do some extra testing on your local:

  • How does it behave during hot reloads?
  • Any console errors?
  • Does it work with multiple edit frames on the same page?

Build or beg,

Marcel


More Stories