Leaf (Leaf v0.2.13)

Copy Markdown View Source

Dual-mode content editor LiveComponent with visual (WYSIWYG) and markdown modes.

Visual mode uses a contenteditable div with vanilla JS (no npm dependencies). Markdown mode uses a plain textarea with toolbar support. Content syncs between modes using Earmark (markdown→HTML) and client-side HTML→markdown conversion.

Usage

import Leaf, only: [leaf_editor: 1]

<.leaf_editor
  id="my-editor"
  content={@content}
  mode={:visual}
  preset={:advanced}
  toolbar={[:image, :video]}
  placeholder="Write something..."
  readonly={false}
  height="480px"
  debounce={400}
/>

Presets

  • :advanced (default) — Full toolbar with all formatting options
  • :simple — Compact toolbar for comments/lightweight editing: undo/redo, bold, italic, strikethrough, inline code, lists, link, emoji, clear formatting

Messages Sent to Parent

  • {:leaf_changed, %{editor_id, markdown, html}} — Content updated
  • {:leaf_insert_request, %{editor_id, type: :image | :video}} — Insert requested

  • {:leaf_mode_changed, %{editor_id, mode: :visual | :markdown}} — Mode switched

Commands from Parent

Use send_update/2:

send_update(Leaf, id: "my-editor", action: :insert_image, url: "https://...", alt: "description")
send_update(Leaf, id: "my-editor", action: :set_content, content: "# Hello")
send_update(Leaf, id: "my-editor", action: :set_mode, mode: :visual)

JS Setup

Add to your app.js:

import "../../../deps/leaf/priv/static/assets/leaf.js"

let Hooks = {
  Leaf: window.LeafHooks.Leaf,
  // ... your other hooks
}

Gettext (optional)

To enable translations, configure a gettext backend:

config :leaf, :gettext_backend, MyApp.Gettext

Otherwise, English strings are used as-is.

Summary

Functions

Renders a Leaf editor as a function component.

Functions

leaf_editor(assigns)

Renders a Leaf editor as a function component.

This is a convenience wrapper around the Leaf LiveComponent. Import it in your view helpers:

import Leaf, only: [leaf_editor: 1]

Then use it in your templates:

<.leaf_editor id="my-editor" content={@content} />

All attributes are passed through to the underlying LiveComponent.

Attributes

  • id (:string) (required)
  • content (:string) - Defaults to "".
  • mode (:atom) - Defaults to :hybrid. Must be one of :visual, :hybrid, :markdown, or :html.
  • preset (:atom) - Defaults to :advanced. Must be one of :advanced, or :simple.
  • toolbar (:list) - Defaults to [].
  • placeholder (:string) - Defaults to "Write something...".
  • readonly (:boolean) - Defaults to false.
  • height (:string) - Defaults to "480px".
  • debounce (:integer) - Defaults to 400.
  • upload_handler (:any) - Defaults to nil.
  • class (:string) - Defaults to nil.
  • script_nonce (:string) - Defaults to "".
  • loading_preset (:atom) - Defaults to :random. Must be one of :default, :random, :unpuzzling, :brewing, :polishing, :composing, :crafting, or :tidying.
  • loading_text (:string) - Defaults to nil.
  • Global attributes are accepted.