Iced Markdown Editor

A Word-style WYSIWYG Markdown editor widget for iced apps, on desktop and the web.

The editor running in a browser: formatted text with a toolbar on the left, the Markdown source on the right

Iced Markdown Editor is a Rust library that adds a full Markdown editor to any iced app. Users see formatted text, like in a word processor, while your app reads and writes plain CommonMark. It is the editor behind the notes in FloeTask.

Features

  • Pages or full width. Show the document on pages like a word processor (A4, Letter or a custom size, with margins), or let it fill the window.
  • Formatting toolbar. With keyboard shortcuts and Word-style autoformat: type - for a list or # for a heading.
  • Lists and tasks. Nested lists, task lists with clickable checkboxes, block quotes and code blocks.
  • Tables. With column alignment. Tab and Enter move between cells.
  • Two modes, same pages. Switch between the formatted view and the Markdown source at any time.
  • The basics. Zoom, undo and redo, and clipboard support.
  • Five languages. Toolbar and status bar in English, German, French, Spanish and Italian.
  • Optional extras. Syntax highlighting in code blocks (syntect feature) and images (images feature).
The editor in the dark theme showing the document on an A4 page, with the Markdown source alongside
Page mode on A4 paper, in the dark theme.

Correct Markdown

The editor supports CommonMark plus the GitHub extensions for strikethrough, task lists and tables. Every one of the 652 examples in the CommonMark 0.31.2 specification is tested to survive a round trip through the editor.

Usage

Add the crate next to iced:

[dependencies]
iced = "0.14"
iced-markdown-editor = { version = "0.3", features = ["syntect", "images"] }

The editor follows iced’s usual pattern: keep an EditorState in your app, pass its actions to update and render it in view.

use iced_markdown_editor::{markdown_editor, Action, EditorState, Event};

struct App {
    editor: EditorState,
}

#[derive(Debug, Clone)]
enum Message {
    Editor(Action),
}

impl App {
    fn update(&mut self, message: Message) -> iced::Task<Message> {
        let Message::Editor(action) = message;
        let output = self.editor.update(action);
        if output.events.contains(&Event::Changed) {
            let markdown = self.editor.markdown(); // save it
        }
        output.task.map(Message::Editor)
    }

    fn view(&self) -> iced::Element<'_, Message> {
        markdown_editor(&self.editor).view().map(Message::Editor)
    }
}

The repository includes examples for a full demo, a minimal setup, several ways of handling images and a version that runs in the browser.

License

Licensed under MIT or Apache 2.0, at your option. The bundled DejaVu fonts have their own licence.