Skip to main content

Configuration

EditorConfig and RendererConfig are the entry points for every customisation. Pass either to Editor.create() or Renderer.render() respectively. Only containerId (and data for the renderer) are required; all other options have safe defaults.

EditorConfig

Pass EditorConfig as the sole argument to Editor.create(). The required containerId must match an existing DOM element id.

OptionTypeRequiredDescription
containerIdstringYesID of the DOM element that will host the editor. Must exist in the DOM before Editor.create() is called.
maxHeightnumberNoMaximum height of the editor in pixels. Set to 0 (the default) for no height limit.
minHeightnumberNoMinimum height of the editor in pixels. Defaults to 300.
onChange(data: EditorData) => voidNoCallback fired whenever the document changes. Receives the full EditorData snapshot.
onReady() => voidNoCallback fired once the editor is fully initialised and ready to accept API calls.
placeholderstringNoPlaceholder text shown when the editor is empty. Defaults to 'Start writing...'.
initialDataEditorDataNoPre-populated EditorData to load when the editor mounts.
initialView'edit' | 'preview' | 'json'NoStarting view mode. One of: edit, preview, json. Defaults to 'edit'.
allowJsonViewEditingbooleanNoWhen true, the JSON view is editable and changes propagate back into the document. Defaults to false.
marginsBlockMarginsNoGlobal top and bottom margin (in pixels) applied to every block. Per-block configs take precedence.
stylesEditorStylesNoEditorStyles object for fine-grained CSS customisation of editor chrome (toolbars, dialogs, controls).
classNamesEditorClassNamesNoEditorClassNames object to attach CSS class names to editor chrome elements.
imageUploaderUploadFunctionNoAsync function that uploads an image file and returns a public URL string.
audioUploaderUploadFunctionNoAsync function that uploads an audio file and returns a public URL string.
videoUploaderUploadFunctionNoAsync function that uploads a video file and returns a public URL string.
fileUploaderUploadFunctionNoUpload function that moves file block attachments into your storage.
localestringNoThe single locale the editor edits. Multilingual blocks are flattened to this locale.
defaultLocalestringNoFallback locale used when a block has no content for the requested locale.
onLocaleFallback(info: { blockId: string; locale: string }) => voidNoCalled when a block falls back to another locale, so the host can show an indicator.
onInlineRewrite(selection: string, action: InlineRewriteAction) => Promise<string | null>NoFunction that rewrites the selected text with AI; when set, the toolbar shows the rewrite button.
inlineRewriteLabelsPartial<Record<InlineRewriteAction, string>>NoOverrides the rewrite menu action labels, for localisation.
inlineRewriteTooltipstringNoOverrides the rewrite wand tooltip on the inline toolbar, for localisation.
blockToolLabelsPartial<Record<BlockToolType, string>>NoOverrides block tool labels in the toolbox and slash menu, for localisation.
blockToolbarLabelsPartial<Record<BlockToolbarLabel, string>>NoOverrides block toolbar texts (add, move, delete, and the rest), for localisation.
resolveLink(url: string) => Promise<Partial<EmbedData>>NoFills a pasted embed’s snapshot from your server: title, Drive file, gist files, or the reason a live view is not possible. A lookup that throws draws the card as the tool not answering, with Try again beside it.
onEmbedAction(action: EmbedAction, blockId: string) => voidNoThe fix beside a card’s reason that only the host can perform: connectGoogle sends the member to connect their Google account; retry the editor handles itself.
disabledEmbedProvidersreadonly string[]NoThe workspace’s switched-off embed tools by wire key (figma, miro, loom, google_drive, github_gist); their links draw as cards that say why.
pasteEmbeds'live' | 'offer' | 'card'NoWhat pasting a supported link does: show it live (the default), offer to, or show a card.
embedLabelsPartial<Record<EmbedLabel, string>>NoTranslated words for the embed block’s reason lines, actions and gist labels, keyed by EmbedLabel; English fallbacks otherwise.
resolveIssues(urls: string[]) => Promise<Record<string, IssueSnapshot>>NoAnswers a page’s issue links with their snapshots, keyed by URL. Absent, chips and cards keep what the document stored and nothing refreshes.
onIssueAction(action: IssueAction, tool: string) => voidNoThe fix beside an issue reason that only the host can perform: connecting the tool, which lands on the host’s Integrations page.
issueCards'off' | 'on'NoWhether an issue link pasted on its own line becomes a card; off when absent. A chip in a sentence is always a chip.
issueChip{ assignee: boolean; status: boolean }NoThe member’s two chip switches: the status pill and the assignee. Both on when absent.
issueLabelsPartial<Record<IssueLabel, string>>NoTranslated words for the issue chip, the card and the Linked issues table, keyed by IssueLabel; English fallbacks otherwise.
jiraSitesreadonly string[]NoThe URLs of the Jira sites the workspace’s connections reach, so a link on a site’s own domain is recognised as an issue.
theme'auto' | 'light' | 'dark'NoColour scheme. One of: auto (follows system), light, dark. Defaults to auto.
themeOverrides{ light?: ThemeTokens; dark?: ThemeTokens }NoPer-mode token overrides. Supply light and/or dark token maps to customise colours without replacing the full theme.
TypeScript
import { Editor } from '@clepit/core';

const editor = Editor.create({
  containerId: 'editor',
  minHeight: 400,
  placeholder: 'Start writing...',
  theme: 'auto',
  onChange: data => console.log(data),
  onReady: () => console.log('Editor ready'),
  imageUploader: async file => {
    const form = new FormData();
    form.append('file', file);
    const res = await fetch('/api/upload', { body: form, method: 'POST' });
    const { url } = await res.json();
    return url;
  },
});

RendererConfig

Pass RendererConfig as the sole argument to Renderer.render(). Both containerId and data are required.

OptionTypeRequiredDescription
containerIdstringYesID of the DOM element where the rendered output will be injected.
dataEditorDataYesThe EditorData document to render. Required.
marginsBlockMarginsNoGlobal top and bottom margin (in pixels) applied to every rendered block.
stylesBlockStylesNoBlockStyles map for per-block-type CSS customisation of rendered output.
classNamesBlockClassNamesNoBlockClassNames map for per-block-type CSS class names on rendered output.
editorClassNamesEditorClassNamesNoEditorClassNames passed through to blocks that render interactive components (e.g. tooltip classNames for paragraphs).
configsPartial<BlockTypeOutputConfigs>NoPartial map of per-block OutputConfig objects. Each entry can set block-level margins and tooltip class names.
theme'auto' | 'light' | 'dark'NoColour scheme. One of: auto, light, dark.
themeOverrides{ light?: ThemeTokens; dark?: ThemeTokens }NoPer-mode token overrides for the rendered output.
TypeScript
import { Renderer } from '@clepit/core';
import type { EditorData } from '@clepit/core';

const data: EditorData = await fetch('/api/content/123').then(r => r.json());

Renderer.render({
  containerId: 'output',
  data,
  theme: 'auto',
  margins: { bottom: 16, top: 16 },
});

Block-level styling

Both EditorConfig and RendererConfig accept styles, classNames, and configs keyed by block type. Use these for targeted overrides; see the Themes page for the complete per-token reference.

TypeScript
import { Editor, Renderer } from '@clepit/core';
import type { BlockStyles, BlockClassNames, EditorStyles } from '@clepit/core';

const editorStyles: EditorStyles = {
  blockToolbar: { container: { borderRadius: '8px' } },
};

const blockStyles: BlockStyles = {
  header: { h1: { fontFamily: 'Georgia, serif' } },
  paragraph: { lineHeight: '1.75' },
  table: { cell: { padding: '8px 12px' } },
};

const blockClassNames: BlockClassNames = {
  paragraph: 'prose-paragraph',
  header: { h1: 'prose-h1', h2: 'prose-h2' },
  alert: { info: 'alert-info', error: 'alert-error' },
};

Editor.create({
  containerId: 'editor',
  styles: editorStyles,
});

Renderer.render({
  containerId: 'output',
  data,
  styles: blockStyles,
  classNames: blockClassNames,
});