Rich text editor system for Phoenix LiveView. 170+ components across 12 modules — from low-level formatting controls to complete preset editors. Designed around TipTap/ProseMirror patterns but implemented entirely in Elixir/HEEx with vanilla JS hooks — no npm runtime dependencies.

Module Overview

ModuleImportComponentsDescription
PhiaUi.Components.Editorimport PhiaUi.Components.Editor19Core toolbar, bubble/floating menus, slash commands, find-replace
PhiaUi.Components.Editor.RichEditorimport PhiaUi.Components.Editor.RichEditor6Rich editor shell, toolbar, content area, floating/slash menus
PhiaUi.Components.Editor.Blocksimport PhiaUi.Components.Editor.Blocks9Task list, callout, collapsible section, columns layout, page break
PhiaUi.Components.Editor.MediaBlocksimport PhiaUi.Components.Editor.MediaBlocks8Image (with resize), table tools, equation editor, diagram, drawing canvas, embed
PhiaUi.Components.Editor.ContentBlocksimport PhiaUi.Components.Editor.ContentBlocks14Toggle list, tab block, video/audio, bookmark card, math block, social embed, PDF viewer, map embed
PhiaUi.Components.Editor.BlockControlsimport PhiaUi.Components.Editor.BlockControls4Block add button, conversion menu, block toolbar, drag indicator
PhiaUi.Components.Editor.AdvancedBlocksimport PhiaUi.Components.Editor.AdvancedBlocks5Synced block, columns block, code sandbox, A4 page, page header/footer
PhiaUi.Components.Editor.Formattingimport PhiaUi.Components.Editor.Formatting16Bold, italic, underline, strikethrough, highlight, subscript, superscript, alignment, lists, etc.
PhiaUi.Components.Editor.FormattingToolbarimport PhiaUi.Components.Editor.FormattingToolbar1Assembled formatting toolbar component
PhiaUi.Components.Editor.Extensionsimport PhiaUi.Components.Editor.Extensions10Track changes, search/nav, export, AI assistant bridge
PhiaUi.Components.Editor.TextDirectionimport PhiaUi.Components.Editor.TextDirection2RTL/LTR toggle, bidirectional text block
PhiaUi.Components.Editor.LanguageToolsimport PhiaUi.Components.Editor.LanguageTools4Grammar panel, grammar suggestion, spell check toggle, dictionary panel
PhiaUi.Components.Editor.Presetsimport PhiaUi.Components.Editor.Presets105 original + 5 v2 preset editors
PhiaUi.Components.Editor.Academicimport PhiaUi.Components.Editor.Academic~8Citation toolbar, reference list, footnotes
PhiaUi.Components.Editor.WritingToolsimport PhiaUi.Components.Editor.WritingTools~6Focus mode, typewriter scroll, distraction-free
PhiaUi.Components.Editor.SearchNavimport PhiaUi.Components.Editor.SearchNav~4Document outline navigation, search within editor
PhiaUi.Components.Editor.TrackChangesimport PhiaUi.Components.Editor.TrackChanges~5Track changes UI, accept/reject, change markers
PhiaUi.Components.Editor.Exportimport PhiaUi.Components.Editor.Export~4Export to PDF/HTML/Markdown, print layout
PhiaUi.Components.Editor.AiAssistantimport PhiaUi.Components.Editor.AiAssistant~4AI writing assistant, autocomplete, rewrite
PhiaUi.Components.Editor.DocumentShellimport PhiaUi.Components.Editor.DocumentShell~4Document shell, sidebar, status bar
PhiaUi.Components.Editor.EditorContentimport PhiaUi.Components.Editor.EditorContent~6Editor content area, block rendering

Preset Editors

The fastest way to use the editor system — drop in a single component:

<%!-- Notion-style: slash commands, drag handles, block toolbars --%>
<.notion_editor id="notion" name="doc[body]" value={@body} />

<%!-- Google Docs-style: menu bar, A4 pages, track changes --%>
<.google_docs_editor id="gdocs" name="doc[body]" value={@body} />

<%!-- Medium-style: floating toolbar, clean reading, images --%>
<.medium_editor_v2 id="medium" name="post[body]" value={@body} />

<%!-- Developer notes: syntax highlighting, code sandbox --%>
<.code_notes_editor id="notes" name="note[body]" value={@body} />

<%!-- Full collaboration: presence, cursors, comments --%>
<.collaborative_editor id="collab" name="doc[body]" value={@body} room_id="doc-123" />

See also: Rich Editor v2 Tutorial


Core Editor Components (PhiaUi.Components.Editor)

import PhiaUi.Components.Editor

editor_toolbar/1

Module: PhiaUi.Components.Editor Tier: interactive

Full-width formatting toolbar container. Groups toolbar buttons and separators into a bordered strip.

Attributes

AttrTypeDefaultDescription
class:stringnilAdditional CSS classes

Usage

<.editor_toolbar>
  <.toolbar_button icon="bold" label="Bold" active={false} />
  <.toolbar_separator />
  <.toolbar_button icon="link" label="Link" />
</.editor_toolbar>

toolbar_button/1

Module: PhiaUi.Components.Editor Tier: interactive

Individual toolbar action button with active and disabled states.

Attributes

AttrTypeDefaultDescription
icon:stringrequiredLucide icon name
label:stringrequiredAccessible label (shown as tooltip)
active:booleanfalseWhether this format is currently applied
disabled:booleanfalseDisables the button
on_click:stringnilphx-click event name
class:stringnilAdditional CSS classes

Usage

<.toolbar_button icon="bold" label="Bold" active={@bold_active} on_click="toggle_bold" />

toolbar_group/1

Module: PhiaUi.Components.Editor Tier: interactive

Visually grouped set of toolbar buttons sharing a common border and background.

Attributes

AttrTypeDefaultDescription
class:stringnilAdditional CSS classes

Usage

<.toolbar_group>
  <.toolbar_button icon="align-left" label="Align left" />
  <.toolbar_button icon="align-center" label="Center" />
  <.toolbar_button icon="align-right" label="Align right" />
</.toolbar_group>

toolbar_separator/1

Module: PhiaUi.Components.Editor Tier: primitive

Vertical divider between toolbar groups.

Attributes

AttrTypeDefaultDescription
class:stringnilAdditional CSS classes

Usage

<.toolbar_separator />

bubble_menu/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaBubbleMenu

Floating selection toolbar that appears when text is selected inside an editor container. Positions itself near the selection using getBoundingClientRect.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
target:stringrequiredCSS selector of the editor element to observe
class:stringnilAdditional CSS classes

Usage

<.bubble_menu id="editor-bubble" target="#my-editor">
  <.toolbar_button icon="bold" label="Bold" />
  <.toolbar_button icon="italic" label="Italic" />
  <.toolbar_button icon="link" label="Link" />
</.bubble_menu>

floating_menu/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaFloatingMenu

Contextual menu floating near the cursor. Appears when cursor is at the start of an empty line.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
target:stringrequiredCSS selector of the editor element
class:stringnilAdditional CSS classes

Usage

<.floating_menu id="editor-float" target="#my-editor">
  <.toolbar_button icon="image" label="Insert image" />
  <.toolbar_button icon="table" label="Insert table" />
</.floating_menu>

slash_command_menu/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaSlashCommand

/command trigger menu for inserting content blocks. Appears when / is typed at the start of a line.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
items:listrequiredList of command maps: %{id, label, description, icon}
on_select:stringrequiredphx-click event fired with phx-value-id
class:stringnilAdditional CSS classes

Usage

<.slash_command_menu
  id="slash-menu"
  items={[
    %{id: "heading", label: "Heading 1", description: "Large section title", icon: "heading-1"},
    %{id: "code", label: "Code Block", description: "Fenced code block", icon: "code"},
    %{id: "image", label: "Image", description: "Upload or embed image", icon: "image"}
  ]}
  on_select="insert_block"
/>

inline_edit/1

Module: PhiaUi.Components.Editor Tier: interactive

Click-to-edit inline text field. Renders a preview span; on click, switches to an input. Confirms on Enter or blur, cancels on Escape.

Attributes

AttrTypeDefaultDescription
id:stringrequiredUnique ID
value:stringrequiredCurrent text value
on_submit:stringrequiredphx-click event for save
placeholder:string"Click to edit"Placeholder text
class:stringnilAdditional CSS classes

Usage

<.inline_edit id="title-edit" value={@title} on_submit="update_title" />

inline_edit_group/1

Module: PhiaUi.Components.Editor Tier: interactive

Group of related inline-editable fields with a shared label row.

Attributes

AttrTypeDefaultDescription
label:stringnilGroup label
class:stringnilAdditional CSS classes

Usage

<.inline_edit_group label="Project Details">
  <.inline_edit id="name-edit" value={@project.name} on_submit="update_name" />
  <.inline_edit id="desc-edit" value={@project.description} on_submit="update_desc" />
</.inline_edit_group>

editor_color_picker/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaEditorColorPicker

Color picker for text color and highlight formatting in the editor toolbar.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
label:string"Color"Button label
on_select:stringrequiredphx-click event fired with phx-value-color
class:stringnilAdditional CSS classes

Usage

<.editor_color_picker id="text-color" label="Text Color" on_select="set_text_color" />

editor_toolbar_dropdown/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaEditorDropdown

Dropdown menu for toolbar (heading level selector, font size picker).

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
label:stringrequiredButton label
options:listrequiredList of %{value, label} option maps
on_select:stringrequiredphx-click event fired with phx-value-value
class:stringnilAdditional CSS classes

Usage

<.editor_toolbar_dropdown
  id="heading-picker"
  label="Paragraph"
  options={[
    %{value: "p", label: "Paragraph"},
    %{value: "h1", label: "Heading 1"},
    %{value: "h2", label: "Heading 2"},
    %{value: "h3", label: "Heading 3"}
  ]}
  on_select="set_block_type"
/>

Module: PhiaUi.Components.Editor Tier: interactive

Link insert/edit dialog for the editor. Contains URL and optional text inputs with insert/remove actions.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for PhiaDialog hook
open:booleanfalseWhether the dialog is open
href:stringnilPre-filled href value
on_insert:stringrequiredphx-click event for inserting the link
on_remove:stringnilphx-click event for removing the link
class:stringnilAdditional CSS classes

Usage

<.editor_link_dialog id="link-dialog" open={@link_dialog_open} on_insert="insert_link" on_remove="remove_link" />

editor_code_block/1

Module: PhiaUi.Components.Editor Tier: widget

Syntax-highlighted code block with language label and optional copy button.

Attributes

AttrTypeDefaultDescription
language:string"text"Language identifier label
code:stringrequiredCode content to display
show_copy:booleantrueShow copy button
class:stringnilAdditional CSS classes

Usage

<.editor_code_block language="elixir" code={@snippet} />

editor_character_count/1

Module: PhiaUi.Components.Editor Tier: widget

Live character and word count display for an editor field.

Attributes

AttrTypeDefaultDescription
chars:integerrequiredCurrent character count
words:integernilCurrent word count (optional)
max_chars:integernilMaximum character limit
class:stringnilAdditional CSS classes

Usage

<.editor_character_count chars={@char_count} words={@word_count} max_chars={5000} />

markdown_editor/1

Module: PhiaUi.Components.Editor Tier: widget Hook: PhiaMarkdownEditor

Split-pane markdown editor with live HTML preview. Left pane is a <textarea>; right pane renders the parsed HTML.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
name:stringrequiredForm field name
value:string""Initial markdown content
height:string"400px"Editor height
class:stringnilAdditional CSS classes

Usage

<.markdown_editor id="post-editor" name="post[body]" value={@post.body} height="600px" />

rich_text_viewer/1

Module: PhiaUi.Components.Editor Tier: primitive

Read-only HTML content renderer with prose typography. Uses Phoenix.HTML.raw/1 — caller must sanitize content.

Attributes

AttrTypeDefaultDescription
content:stringrequiredSanitized HTML content string
class:stringnilAdditional CSS classes

Usage

<.rich_text_viewer content={@post.html_body} class="max-w-prose" />

Security note: Always sanitize HTML with HtmlSanitizeEx or equivalent before passing to rich_text_viewer.


editor_find_replace/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaEditorFindReplace

Slide-in find-and-replace panel for inline text editing. Supports regex mode, match-case, and replace-all.

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
target:stringrequiredCSS selector of the editor element
open:booleanfalseWhether the panel is visible
class:stringnilAdditional CSS classes

Usage

<.editor_find_replace id="find-replace" target="#my-editor" open={@find_open} />

editor_word_count/1

Module: PhiaUi.Components.Editor Tier: widget

Word count display with estimated reading time.

Attributes

AttrTypeDefaultDescription
words:integerrequiredCurrent word count
reading_speed:integer200Words per minute for reading time estimate
class:stringnilAdditional CSS classes

Usage

<.editor_word_count words={@word_count} />

advanced_editor/1

Module: PhiaUi.Components.Editor Tier: interactive Hook: PhiaAdvancedEditor

Full-featured ProseMirror-inspired rich text editor. Includes toolbar, bubble menu, slash commands, link dialog, and find-replace — assembled in a single composable component. Inspired by TipTap (the most popular ProseMirror wrapper, used by Notion, Linear, and Vercel).

Attributes

AttrTypeDefaultDescription
id:stringrequiredRequired for hook
name:stringrequiredHidden form field name for serialized content
value:string""Initial HTML content
height:string"400px"Editor height
show_toolbar:booleantrueShow formatting toolbar
show_word_count:booleantrueShow word count footer
class:stringnilAdditional CSS classes

Usage

<.advanced_editor id="article-editor" name="article[body]" value={@article.body} height="500px" />

LiveView Example

def mount(_params, _session, socket) do
  article = Articles.get!(1)
  {:ok, assign(socket, article: article)}
end

def handle_event("save", %{"article" => params}, socket) do
  case Articles.update(socket.assigns.article, params) do
    {:ok, article} -> {:noreply, assign(socket, article: article)}
    {:error, changeset} -> {:noreply, assign(socket, changeset: changeset)}
  end
end
<.form for={@form} phx-submit="save">
  <.advanced_editor id="body-editor" name="article[body]" value={@article.body} />
  <.button type="submit">Publish</.button>
</.form>

Rich Editor (PhiaUi.Components.Editor.RichEditor)

import PhiaUi.Components.Editor.RichEditor

The v2 rich editor shell — a composable editor with toolbar, content area, and floating menus. Powered by the PhiaEditor v2 JS engine (~1,200 LOC).

ComponentTierHookDescription
rich_editorinteractivePhiaRichEditorMain editor shell with toolbar/content slots
rich_toolbarinteractiveToolbar container for the rich editor
rich_contentinteractiveContent area with block rendering
rich_floating_menuinteractiveFloating block insert menu
rich_slash_commandinteractiveSlash command menu for rich editor
rich_bubble_toolbarinteractiveSelection-aware floating toolbar

Usage

<.rich_editor id="my-editor" name="content[body]" value={@body}>
  <:toolbar>
    <.formatting_toolbar editor_id="my-editor" />
  </:toolbar>
</.rich_editor>

Editor Blocks (PhiaUi.Components.Editor.Blocks)

import PhiaUi.Components.Editor.Blocks

Structural block types for the editor.

ComponentDescription
task_listInteractive checklist with checkboxes
task_list_itemIndividual task item
callout_blockHighlighted callout with icon and color
collapsible_sectionExpandable/collapsible content section
columns_layoutMulti-column content layout
columnIndividual column in a columns layout
page_breakVisual page break separator
horizontal_ruleThemed horizontal divider
block_quoteStyled blockquote for the editor

Media Blocks (PhiaUi.Components.Editor.MediaBlocks)

import PhiaUi.Components.Editor.MediaBlocks

Rich media embedding blocks.

ComponentHookDescription
image_blockPhiaImageResizeImage with resize handles, caption, alignment
table_blockPhiaTableEditorInteractive table with add/remove rows/cols
equation_editorPhiaEquationRendererKaTeX math equation editor
diagram_blockPhiaDiagramRendererMermaid diagram renderer
drawing_canvasPhiaDrawingCanvasFreehand drawing canvas
embed_blockoEmbed content embedding
code_block_enhancedPhiaCodeHighlightSyntax-highlighted code with language selector
emoji_picker_blockPhiaEmojiPickerBlockInline emoji picker

Content Blocks (PhiaUi.Components.Editor.ContentBlocks) — v0.1.17

import PhiaUi.Components.Editor.ContentBlocks
ComponentDescription
toggle_listExpandable list items (FAQ-style)
toggle_list_itemIndividual toggle item
tab_blockTabbed content container
tab_block_itemIndividual tab panel
video_blockVideo embed with controls
audio_blockAudio player block
bookmark_cardURL bookmark with preview
math_blockDisplay math (block-level KaTeX)
social_embedTwitter/YouTube/etc embed
pdf_viewerInline PDF viewer
map_embedMap embed block
file_attachmentFile attachment block
divider_blockDecorative divider with styles
table_of_contents_blockAuto-generated TOC from headings

Block Controls (PhiaUi.Components.Editor.BlockControls) — v0.1.17

import PhiaUi.Components.Editor.BlockControls
ComponentHookDescription
block_add_button"+" button to insert new blocks
block_conversion_menuMenu to convert block types (paragraph to heading, etc.)
block_toolbarFloating toolbar for selected blocks
block_drag_indicatorPhiaDragHandleDrag handle for reordering blocks

Advanced Blocks (PhiaUi.Components.Editor.AdvancedBlocks) — v0.1.17

import PhiaUi.Components.Editor.AdvancedBlocks
ComponentDescription
synced_blockBlock synced across multiple locations
columns_blockAdvanced multi-column layout with resize
code_sandboxInteractive code sandbox with preview
a4_pageA4-sized page container for document layout
page_header_footerHeader/footer for A4 page mode

Formatting (PhiaUi.Components.Editor.Formatting)

import PhiaUi.Components.Editor.Formatting

16 individual formatting control components. Each fires a phx-click event to toggle formatting.

ComponentDescription
bold_buttonToggle bold
italic_buttonToggle italic
underline_buttonToggle underline
strikethrough_buttonToggle strikethrough
highlight_buttonToggle text highlight
subscript_buttonToggle subscript
superscript_buttonToggle superscript
code_buttonToggle inline code
link_buttonInsert/edit link
align_left_buttonAlign text left
align_center_buttonCenter text
align_right_buttonAlign text right
align_justify_buttonJustify text
bullet_list_buttonToggle bullet list
ordered_list_buttonToggle ordered list
clear_formatting_buttonClear all formatting

Text Direction (PhiaUi.Components.Editor.TextDirection) — v0.1.17

import PhiaUi.Components.Editor.TextDirection
ComponentDescription
text_direction_toggleToggle between LTR and RTL text direction
bidi_text_blockBidirectional text block with auto-detection

Language Tools (PhiaUi.Components.Editor.LanguageTools) — v0.1.17

import PhiaUi.Components.Editor.LanguageTools
ComponentDescription
grammar_panelGrammar checking panel with suggestions
grammar_suggestionIndividual grammar suggestion item
spell_check_toggleToggle spell checking on/off
dictionary_panelDictionary/thesaurus lookup panel

Extensions (PhiaUi.Components.Editor.Extensions)

import PhiaUi.Components.Editor.Extensions
ComponentHookDescription
track_changes_panelPhiaTrackChangesTrack changes sidebar with accept/reject
search_navDocument search and navigation
export_menuExport to PDF/HTML/Markdown menu
ai_assistant_panelAI writing assistant sidebar
version_historyDocument version history viewer
comments_sidebarInline comments sidebar
outline_panelDocument outline/structure panel
word_count_barBottom bar with word/char/page counts
reading_timeEstimated reading time display
focus_modeDistraction-free writing mode

Presets (PhiaUi.Components.Editor.Presets)

import PhiaUi.Components.Editor.Presets

Original Presets (v0.1.17)

PresetDescription
simple_editorMinimal editor with bold/italic/link/lists toolbar
article_editorMedium-style editor for blog posts and articles
document_editor_fullFull document shell with header/footer/sidebar
academic_editorAcademic editor with citation toolbar
email_composerEmail-style editor with To/Subject/Signature

v2 Presets (v0.1.17)

PresetDescription
notion_editorNotion-style: slash commands, drag, block toolbars
google_docs_editorGDocs: menu bar, A4 pages, track changes
medium_editor_v2Medium: floating toolbar, clean reading, images
code_notes_editorDev notes: syntax highlighting, code sandbox, markdown
collaborative_editorFull collab: presence, cursors, comments sidebar

Usage

<.notion_editor
  id="my-editor"
  name="document[body]"
  value={@document.body}
  placeholder="Type / for commands..."
/>

JS Hooks

The editor system ships with 10+ JS hooks in v0.1.17:

HookFileDescription
PhiaRichEditorphia_rich_editor.jsCore editor engine (v2, ~1,200 LOC)
PhiaEditorV2phia_editor_v2.jsEditor v2 lifecycle management
PhiaEditorBundlephia_editor_bundle.jsBundled editor with all extensions
PhiaCodeHighlightcode_highlight.jsSyntax highlighting for code blocks
PhiaImageResizeimage_resize.jsImage resize handles
PhiaTableEditortable_editor.jsInteractive table editing
PhiaEquationRendererequation_renderer.jsKaTeX equation rendering
PhiaDiagramRendererdiagram_renderer.jsMermaid diagram rendering
PhiaDrawingCanvasdrawing_canvas.jsFreehand drawing canvas
PhiaDragHandledrag_handle.jsBlock drag-and-drop
PhiaEmojiPickerBlockemoji_picker_block.jsEmoji picker popup
PhiaFormatPainterformat_painter.jsFormat painter tool
PhiaTrackChangestrack_changes.jsTrack changes engine
PhiaRibbonToolbarribbon_toolbar.jsMicrosoft-style ribbon toolbar
PhiaCollabphia_collab.jsCollaborative editing bridge