DemoDocsPlaygroundGitHub

An extensible rich text editor framework built on Lexical. Ship faster with production-ready defaults and TypeScript-first APIs.

Documentation

IntroductionInstallation@lyfie/luthor-headless@lyfie/luthor

Resources

DemoFeaturesPlaygroundGitHubluthor @ npmluthor-headless @ npm

Support the Project

Buy me a coffeeStar on GitHub

Built with ❤️ by Lyfie.org

HomeDocsFeaturesDemoGitHubllms.txtllms-full.txt
  1. Home
  2. Docs
  3. Luthor
  4. Props Reference

Luthor Documentation

Getting Started

  • Introduction
  • Installation
  • Contributor Guide
  • AI Agents and Vibe Coding
  • Capabilities
  • @lyfie/luthor-headless
  • @lyfie/luthor

@lyfie/luthor-headless

  • Architecture
  • Extensions and API
  • Metadata Comment System
  • Features
  • Typography and Text
  • Structure and Lists
  • Media and Embeds
  • Code and Devtools
  • Interaction and Productivity
  • Customization and Theming

@lyfie/luthor

  • Architecture
  • Props Reference
  • Feature Flags
  • Presets
  • Extensive Editor
  • Compose Editor
  • Simple Editor
  • Legacy Rich Editor
  • MD Editor
  • HTML Editor
  • Slash Editor
  • Headless Editor

Props Reference

This page is the full prop contract for @lyfie/luthor presets.

  • Base preset: ExtensiveEditor
  • Wrapper presets: ComposeEditor, SimpleEditor, LegacyRichEditor, MDEditor, HTMLEditor, SlashEditor, HeadlessEditorPreset

1) ExtensiveEditorProps (base contract)

Content and mode

PropTypeDefaultNotes
defaultContentstringundefinedInjected on ready when present.
showDefaultContentbooleantrueWhen true and defaultContent is empty, ships with welcome JSON content.
placeholderstring | { visual?: string; json?: string; markdown?: string; html?: string }"Write anything..."Source modes have dedicated default placeholders.
initialMode'visual-only' | 'visual-editor' | 'visual' | 'json' | 'markdown' | 'html''visual-editor'visual is accepted and normalized to visual-editor.
defaultEditorViewsame as initialModeundefinedIf set, overrides initialMode for first view.
availableModesreadonly ExtensiveEditorMode[]['visual-editor', 'visual-only', 'json', 'markdown', 'html']Invalid initial/default mode falls back to first available mode.
isEditorViewTabsVisiblebooleantruePreferred prop name for mode tabs visibility.
isEditorViewsTabVisiblebooleanundefinedLegacy alias; used when preferred prop is not provided.

Lifecycle and ref

PropTypeDefaultNotes
onReady(methods: ExtensiveEditorRef) => voidundefinedCalled when editor methods are ready.

ExtensiveEditorRef methods:

  • injectJSON(content: string): void
  • getJSON(): string
  • getMarkdown(): string
  • getHTML(): string

Toolbar, layout, and visibility

PropTypeDefaultNotes
isToolbarEnabledbooleantrueHides toolbar UI only; command wiring still exists.
isToolbarPinnedbooleanfalseSticky pin behavior for top toolbar region.
toolbarPosition'top' | 'bottom''top'Top is most common for docs/editing UX.
toolbarAlignment'left' | 'center' | 'right''left'Alignment inside toolbar region.
toolbarLayoutToolbarLayoutundefinedUse default/traditional/custom section layouts.
toolbarVisibilityToolbarVisibilityundefinedPer-toolbar-item visibility overrides.
toolbarClassNamestringundefinedClass name for toolbar root.
toolbarStyleVarsToolbarStyleVarsundefinedCSS custom properties for toolbar theme tokens.
classNamestringundefinedClass on preset wrapper root.
variantClassNamestringundefinedClass on preset variant shell.

Feature gating and behavior

PropTypeDefaultNotes
featureFlagsFeatureFlagOverridesundefinedPartial override map for all extensive feature flags.
isDraggableBoxEnabledbooleanundefinedConvenience alias for draggable behavior; merges into featureFlags.draggableBlock.
editOnClickbooleantrueIn visual-only mode, click promotes to editable mode and places caret near click.
syncHeadingOptionsWithCommandsbooleantrueKeeps command palette/slash heading options synced with heading controls.
headingOptionsreadonly ('h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6')[]all levelsFilters available heading levels.
paragraphLabelstring'Paragraph'Label used in command-generated block entry.
isCopyAllowedbooleantrueUsed by code intelligence copy behavior.

Slash, palette, and shortcuts

PropTypeDefaultNotes
slashCommandVisibilitySlashCommandVisibilityundefinedSupports allow/deny filters or explicit selection arrays.
shortcutConfigShortcutConfigundefinedOverride bindings, disable command IDs, collision/native conflict behavior.
commandPaletteShortcutOnlybooleanfalseWhen true, palette shows only commands that currently have shortcuts.

Theme and style system

PropTypeDefaultNotes
initialTheme'light' | 'dark''light'Initial theme state for preset UI.
onThemeChange(theme: 'light' | 'dark') => voidundefinedCalled whenever theme changes.
themePartial<LuthorTheme>undefinedDeep merge into default headless theme.
editorThemeOverridesLuthorEditorThemeOverridesundefinedToken-level CSS var bridge for editor theme.
defaultSettingsDefaultSettingsundefinedHigh-level style defaults (font, link, list, quote, table, hr, placeholder, codeblock, toolbar).
quoteClassNamestringundefinedExtra class merged into quote node styles.
quoteStyleVarsQuoteStyleVarsundefinedQuote visual CSS vars.

Typography and code configuration

PropTypeDefaultNotes
fontFamilyOptionsreadonly FontFamilyOption[]built-in listIncludes default, inter, merriweather, jetbrains-mono by default.
fontSizeOptionsreadonly FontSizeOption[]built-in listIncludes common pixel sizes + default option.
lineHeightOptionsreadonly LineHeightOption[]built-in listIncludes default and common ratios.
minimumDefaultLineHeightstring | number1.5Validated and normalized; invalid values fall back to 1.5.
scaleByRatiobooleanfalseUsed by image resize behavior.
syntaxHighlighting'auto' | 'disabled'extension defaultControls code syntax highlighting behavior.
codeHighlightProviderCodeHighlightProvider | nullundefinedInject a concrete provider implementation.
loadCodeHighlightProvider() => Promise<CodeHighlightProvider | null>undefinedLazy loader for provider implementation.
maxAutoDetectCodeLengthnumberundefinedMax code length for language autodetect.
languageOptionsreadonly string[] | CodeLanguageOptionsConfigundefinedLanguage option list or config object (mode, values).
maxListIndentationnumber8Maximum sub-indent levels below root list level.

2) Preset-specific prop layers

ComposeEditorProps

ComposeEditorProps = Omit<ExtensiveEditorProps, "featureFlags"> & { featureFlags?: FeatureFlagOverrides; compactToolbar?: boolean }

  • Adds:
    • featureFlags?
    • compactToolbar?: boolean (default false)
  • Forces mode profile:
    • availableModes = ["visual", "json"]

SimpleEditorProps

SimpleEditor is a purpose-built message input wrapper and does not expose the full extensive surface directly.

PropTypeDefault
className / variantClassNamestringundefined
initialTheme'light' | 'dark'inherited
onThemeChangecallbackundefined
themePartial<LuthorTheme>undefined
defaultContentstringundefined
showDefaultContentbooleanfalse
placeholderExtensiveEditorProps["placeholder"]undefined
formattingOptions{ bold?: boolean; italic?: boolean; strikethrough?: boolean }all enabled
onSend(payload: SimpleEditorSendPayload) => voidundefined
outputFormat'md' | 'json''md'
clearOnSendbooleantrue
allowEmptySendbooleanfalse
submitOnEnterbooleanfalse
allowShiftEnterbooleantrue
minHeightnumber | string56
maxHeightnumber | string220
minWidthnumber | string240
maxWidthnumber | string'100%'
showBottomToolbarbooleantrue
toolbarButtonsreadonly SimpleToolbarButton[][]
toolbarClassNamestringundefined
toolbarStyleCSSPropertiesundefined
showSendButtonbooleantrue
sendButtonPlacement'inside' | 'right''inside'
sendButtonContentReactNode'Send'
sendButtonAriaLabelstring'Send message'
sendButtonClassNamestringundefined
scrollAreaClassNamestringundefined

SimpleEditorSendPayload:

  • format: 'md' | 'json'
  • text: string (selected output format)
  • markdown: string
  • json: string

LegacyRichEditorProps

LegacyRichEditorProps = Omit<ExtensiveEditorProps, "featureFlags" | "availableModes" | "initialMode" | "defaultEditorView"> & { sourceFormat?: 'markdown' | 'html' | 'both'; initialMode?: LegacyRichEditorMode; defaultEditorView?: LegacyRichEditorMode; featureFlags?: FeatureFlagOverrides }

  • sourceFormat default: 'both'
  • Mode sets by source format:
    • 'both' -> ['visual', 'markdown', 'html']
    • 'markdown' -> ['visual', 'json', 'markdown']
    • 'html' -> ['visual', 'json', 'html']

MDEditorProps

  • Inherits LegacyRichEditorProps
  • Fixes source format to markdown
  • Allowed modes: 'visual' | 'json' | 'markdown'

HTMLEditorProps

  • Inherits LegacyRichEditorProps
  • Fixes source format to html
  • Allowed modes: 'visual' | 'json' | 'html'

SlashEditorProps

SlashEditorProps = Omit<ExtensiveEditorProps, "featureFlags" | "isToolbarEnabled"> & { slashVisibility?: SlashCommandVisibility; isDraggableEnabled?: boolean; featureFlags?: FeatureFlagOverrides; isToolbarEnabled?: boolean }

  • isToolbarEnabled default: false
  • isDraggableEnabled default: true
  • Enforced behavior:
    • slashCommand: true
    • commandPalette: false

HeadlessEditorPresetProps

HeadlessEditorPresetProps = Omit<ExtensiveEditorProps, "featureFlags" | "availableModes" | "initialMode" | "defaultEditorView"> & { initialMode?: 'visual' | 'json' | 'markdown' | 'html'; defaultEditorView?: same; featureFlags?: FeatureFlagOverrides }

  • Allowed modes fixed to: ['visual', 'json', 'markdown', 'html']
  • Uses lightweight feature policy defaults and enforcement.

3) Practical usage patterns

Save all output formats from ref

tsx
import { useRef } from 'react';
import { ExtensiveEditor, type ExtensiveEditorRef } from '@lyfie/luthor';

export function SaveExample() {
  const ref = useRef<ExtensiveEditorRef>(null);

  return (
    <>
      <button
        onClick={() => {
          const methods = ref.current;
          if (!methods) return;
          console.log({
            json: methods.getJSON(),
            markdown: methods.getMarkdown(),
            html: methods.getHTML(),
          });
        }}
      >
        Save
      </button>
      <ExtensiveEditor ref={ref} />
    </>
  );
}

Disable heavy features without changing preset

tsx
<ExtensiveEditor
  featureFlags={{
    image: false,
    table: false,
    iframeEmbed: false,
    youTubeEmbed: false,
    customNode: false,
  }}
/>

Markdown-first editing profile

tsx
<MDEditor initialMode="visual" defaultEditorView="markdown" />

4) Related pages

  • Architecture
  • Feature Flags
  • Presets
Previous: Architecture
Next: Feature Flags