Skip to content

Custom Editor Components (Shortcodes)

While standard Markdown covers basic text formatting, technical documentation often relies on custom components like Starlight’s <Aside> or <Badge>. To make these available to non-technical writers, Sveltia CMS allows developers to register Custom Editor Components via its JavaScript API.


Custom editor components bridge the gap between the visual editor and raw MDX. They allow editors to interact with a structured form inside the CMS, which then serializes cleanly into your custom shortcode or MDX syntax in the underlying file.

Registering a component involves defining three core elements:

  1. Fields: The form inputs presented to the author in the CMS UI.
  2. Pattern Matching (RegExp): How the CMS parses existing shortcodes out of the raw Markdown file.
  3. Serialization (toBlock / fromBlock): Functions that convert between form field states and MDX markup.

To give editors visual control over callout boxes, you can register a custom component inside your CMS initialization script (public/admin/index.html):

Registering the component via CMS.registerEditorComponent.

CMS.registerEditorComponent({
id: 'aside',
label: 'Aside Callout',
fields: [
{
name: 'type',
label: 'Aside Type',
widget: 'select',
options: ['note', 'tip', 'caution', 'danger']
},
{
name: 'content',
label: 'Content',
widget: 'markdown'
}
],
pattern: /^<Aside type="(.*?)">([\s\S]*?)<\/Aside>$/,
fromBlock: function(match) {
return {
type: match[1],
content: match[2]
};
},
toBlock: function(obj) {
return `<Aside type="${obj.type}">\n${obj.content}\n</Aside>`;
},
toPreview: function(obj) {
return `<div class="aside-${obj.type}"><strong>${obj.type.toUpperCase()}</strong>: ${obj.content}</div>`;
}
});

Section titled “Registering a Starlight Link Card Component”

To allow authors to create visual navigation cards pointing to other articles in the CMS, the linkcard editor component provides a dropdown populated with existing articles:

Registering <LinkCard> with an article selection dropdown.

CMS.registerEditorComponent({
id: 'linkcard',
label: 'Starlight Link Card',
fields: [
{
name: 'href',
label: 'Target Article',
widget: 'select',
options: getArticleSelectOptions()
},
{ name: 'title', label: 'Card Title (Optional)', widget: 'string', required: false },
{ name: 'description', label: 'Card Description (Optional)', widget: 'string', required: false }
],
pattern: /^<LinkCard\s+[^>]*?\/>/,
fromBlock: function (match) {
/* Extracts title, href, and description */
},
toBlock: function (obj) {
return `<LinkCard title="${obj.title}" href="${obj.href}" description="${obj.description}" />`;
},
toPreview: function (obj) {
/* Renders Starlight card preview in CMS editor */
}
});