Editor

A structured document editor with formatting, tables, references and host-owned services.

Document editor

A full document editor with persistent formatting controls.

Chip color
Insert paragraph below
Duplicate block
Delete block

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-editor/ui-editor.html"
>

<ui-editor
  label="Article body"
  toolbar-mode="sticky"
  content="{&quot;type&quot;:&quot;doc&quot;,&quot;content&quot;:[{&quot;type&quot;:&quot;paragraph&quot;,&quot;content&quot;:[{&quot;type&quot;:&quot;text&quot;,&quot;text&quot;:&quot;Select words to format them, or type / to insert a block.&quot;}]}]}"
></ui-editor>
<script setup>
  import { UiEditor } from "@threadlabs/looma";
</script>

<template>
  <UiEditor
    label="Article body"
    toolbar-mode="sticky"
    :content="{ type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Select words to format them, or type / to insert a block.' }] }] }"
  />
</template>
import { UiEditor } from "@threadlabs/looma";

export default function Example() {
  return <UiEditor
    label="Article body"
    toolbarMode="sticky"
    content={{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Select words to format them, or type / to insert a block."}]}]}}
  />;
}
/** @jsxImportSource preact */
import { UiEditor } from "@threadlabs/looma";

export default function Example() {
  return <UiEditor
    label="Article body"
    toolbarMode="sticky"
    content={{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Select words to format them, or type / to insert a block."}]}]}}
  />;
}
<script>
  import { UiEditor } from "@threadlabs/looma";
</script>

<UiEditor
  label="Article body"
  toolbarMode="sticky"
  content={{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Select words to format them, or type / to insert a block."}]}]}}
/>
import { Component } from "@angular/core";
import { UiEditor } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiEditor],
  template: `
    <div
      ui-editor
      [label]="'Article body'"
      [toolbarMode]="'sticky'"
      [content]="{ type: 'doc', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Select words to format them, or type / to insert a block.' }] }] }"
    ></div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: div

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
compact-toolbarKeep frequent inline controls visible and put the full inventory behind Format.compactToolbarbooleanfalse—
contentThe controlled Tiptap document. A change reports the updated content.contentobject
  • type: string (required)
{ type: 'doc', content: [{ type: 'paragraph' }] }—
content-densityChoose the padding and minimum height of read-only documents.contentDensitykeywordcomfortablecomfortable, compact
disable-highlightDisable authoring new highlights while retaining saved highlights.disableHighlightbooleanfalse—
editableAllow authoring. Read-only documents can still expose passage actions.editablebooleantrue—
labelAccessible name of the textbox.labelstringDocument—
link-base-urlOrigin used for newly inserted relative links.linkBaseUrlstring—
link-target-labelThe name of a searchable link destination.linkTargetLabelstringItem—
mention-itemsDefault mention choices when nobody answers mention-query.mentionItemslist(object)
  • [].id: string (required)
  • [].label: string (required)
  • [].detail: string
  • [].initials: string
[]—
mention-limitMaximum number of mention suggestions.mentionLimitinteger8—
placeholderThe empty document's writing prompt.placeholderstringType “/” for commands, or start writing…—
range-actionsApplication caret actions with host-owned durable ranges.rangeActionslist(object)
  • [].id: string (required)
  • [].label: string (required)
  • [].from: integer (required)
  • [].to: integer (required)
[]—
referencesCached reference display values. Replacing this map refreshes labels without editing content.referencesobject——
selection-actionsApplication actions available for a selected passage.selectionActionslist(object)
  • [].id: string (required)
  • [].label: string (required)
[]—
toolbar-modeWhere formatting controls appear.toolbarModekeywordbubblebubble, sticky, popover, contextual
toolbar-openControlled popover toolbar visibility.toolbarOpenbooleanfalse—
toolbar-trigger-idExternal trigger for popover mode.toolbarTriggerIdstring—

Framework props

NameTypeDefaultAllowed values
compactToolbarbooleanfalse—
content{ readonly type: string; readonly [name: string]: unknown }
  • type: string (required)
{ type: 'doc', content: [{ type: 'paragraph' }] }—
contentDensity"comfortable" | "compact"comfortablecomfortable, compact
disableHighlightbooleanfalse—
editablebooleantrue—
labelstringDocument—
linkBaseUrlstring—
linkTargetLabelstringItem—
mentionItemsreadonly ({ readonly id: string; readonly label: string; readonly detail?: string | null; readonly initials?: string | null })[]
  • [].id: string (required)
  • [].label: string (required)
  • [].detail: string
  • [].initials: string
[]—
mentionLimitnumber8—
placeholderstringType “/” for commands, or start writing…—
rangeActionsreadonly ({ readonly id: string; readonly label: string; readonly from: number; readonly to: number })[]
  • [].id: string (required)
  • [].label: string (required)
  • [].from: integer (required)
  • [].to: integer (required)
[]—
references{ readonly [name: string]: unknown }——
selectionActionsreadonly ({ readonly id: string; readonly label: string })[]
  • [].id: string (required)
  • [].label: string (required)
[]—
toolbarMode"bubble" | "sticky" | "popover" | "contextual"bubblebubble, sticky, popover, contextual
toolbarOpenbooleanfalse—
toolbarTriggerIdstring—

Events

NameDetailDescription
changeobject
  • content: object (required)
  • content.type: string (required)
Emitted when a toggleable control changes checked state.
image-activateobject
  • src: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
image-rendition-errorobject
  • src: string (required)
  • trigger: keyword (required)
Emitted with the declared detail payload.
range-actionobject({ id: string, ranges: list(object({ from: integer, to: integer })) })Emitted with the declared detail payload.
selection-actionobject({ id: string, from: integer, to: integer, text: string, before: string, after: string })Emitted with the declared detail payload.
toolbar-closeobject({ ... })Emitted with the declared detail payload.
toolbar-openobject({ ... })Emitted with the declared detail payload.
upload-errorobject
  • error: unknown (required)
  • file: unknown (required)
Emitted with the declared detail payload.

Slots

NamePurpose
fallbackNamed content for the fallback region.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

No component tokens.

Shared tokens

No shared tokens.