> It is possible. We have the technology.
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
_84import React from 'react';
_84import { useSitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs';
_84interface FieldEditFrameProps {
_84 disabledIcon?: string;
_84 commandDisplayName?: string;
_84 databaseName?: string;
_84 hideIfNotPageEditing?: boolean;
_84const FieldEditFrame: React.FC<FieldEditFrameProps> = ({
_84 header = 'Edit Fields',
_84 icon = '/temp/iconcache/people/16x16/cubes_blue.png',
_84 disabledIcon = '/temp/cubes_blue_disabled16x16.png',
_84 command = '{70C4EED5-D4CD-4D7D-9763-80C42504F5E7}',
_84 hideIfNotPageEditing,
_84 const { sitecoreContext } = useSitecoreContext();
_84 const { pageEditing, language: sitecoreLanguage, route } = sitecoreContext;
_84 const shouldRender = pageEditing && itemId && fields && fields.length;
_84 if (!shouldRender && hideIfNotPageEditing) {
_84 if (!itemId || !fields) {
_84 // TODO: handle route undefined
_84 const contextItemUri = `sitecore://${databaseName || route?.databaseName}/${itemId}?lang=${
_84 language || sitecoreLanguage
_84 const clickCommandAction = `webedit:fieldeditor(command=${command},fields=${fields.join(
_84 const clickCommand = {
_84 click: `javascript:Sitecore.PageModes.PageEditor.postRequest('${clickCommandAction}',null,false)`,
_84 disabledIcon: disabledIcon,
_84 tooltip: tooltip || `Edit the following fields: ${fields.join(', ')}`,
_84 const commandData = {
_84 commands: [clickCommand],
_84 contextItemUri: contextItemUri,
_84 displayName: commandDisplayName || 'Edit Properties',
_84 expandedDisplayName: '',
_84 sc_item: contextItemUri,
_84 'sc-part-of': 'editframe',
_84 <div className="scLooseFrameZone scEnabledChrome" {...divAttrs}>
_84 <span className="scChromeData">{JSON.stringify(commandData)}</span>
_84export default FieldEditFrame;
Example Implementation
_15import FieldEditFrame from './../../utils/FieldEditFrame';
_15 // of course, its better not to hardcode these values
_15 itemId="{FEA43559-D12F-47C9-911C-8170B7FAEFA4}"
_15 fields={['Alert Label']}
_15 <h2>Goo Goo Ga Ga</h2>
Now the element is clickable:
And clicking the blocks icon opens the 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