On this page
Import
import {
Markdown,
MarkdownEditor,
} from '@envsemble/envui/markdown';
Usage
Markdown and MarkdownEditor come from @envsemble/envui/markdown. Markdown renders the string in children: CommonMark with tables, strikethrough, task lists, automatic links and footnotes.
- Raw HTML is ignored, except keys written as
<kbd>, which render as Kbd. headingOffsetadds to the document's heading levels, capped at h6: set it so the first heading sits one level below the page's.codeCopyablegives each code block a copy button.
import { Markdown } from '@envsemble/envui/markdown';
const note = `## Launch checklist
Prepare **Northwind** for the spring launch.
- Confirm the pricing with Priya Shah.
- Review the [launch plan](/documents/launch-plan) before sharing it.
- Keep the original notes.
On launch day:
1. Publish the pricing page.
2. Send the release notes.
> Share the plan once the review is done.
| Task | Owner | Status |
| --- | --- | --- |
| Pricing page | Sam Lee | Ready |
| Release notes | Alex Morgan | In review |
- [x] Outline written
- [ ] Review scheduled
Save a draft with <kbd>Ctrl</kbd>+<kbd>S</kbd>, then build:
\`\`\`sh
npm run build
\`\`\`
`;
export default function ProjectNote() {
// The note sits under the page's h2, so its headings start one level lower.
return (
<Markdown headingOffset={1} codeCopyable>
{note}
</Markdown>
);
}Links
renderLink renders each link from its safe href and native anchor props, such as to open some in a panel; keep a real anchor with its destination, so modified clicks stay the browser's.
<Markdown
renderLink={({ href, children, ...props }) => (
<Link {...props} href={href} onClick={openDocumentLinksInPanel}>
{children}
</Link>
)}
>
{text}
</Markdown>
Your own elements
components replaces how an element renders, merged over envUI's own, with the application's winning; native props such as id and className reach the element.
remarkPluginsrun after envUI's own Markdown extensions, andrehypePluginsafter raw HTML is dropped; envUI adds no rehype plugins of its own.- Don't render untrusted Markdown with a plugin that brings raw HTML back.
<Markdown
components={{
blockquote: ({ node: _node, children }) => <Alert title="Rule">{children}</Alert>,
}}
>
{text}
</Markdown>
The editor
MarkdownEditor is a Textarea with a toolbar and Write and Preview tabs.
- Leave it uncontrolled with
defaultValue, which a form reset restores, or control it withvalueandonValueChange, which receives the whole source after typing, formatting, undo or redo; replacingvalueclears the undo history. - It takes Textarea's
label,description,errorandrows, andvariantisoutline, the default, orghost. sizingisfixed, the default, which keeps the height and scrolls, orcontent, which grows with the text.preview={false}hides the tabs, andpreviewPropspassesheadingOffset,renderLinkandcodeCopyableto the Markdown of the preview.
<MarkdownEditor
label="Description"
sizing="content"
rows={4}
value={description}
onValueChange={setDescription}
previewProps={{ headingOffset: 2 }}
/>
Toolbar and link picker
toolbar lists the actions, of heading, bold, italic, inline-code, bullet-list, numbered-list, quote, code-block and link, shown in that order, grouped by kind; undo and redo come with a visible toolbar, and toolbar={false} hides it. pickLink opens the application's own link picker: it receives the selectedText and returns a MarkdownLink, { label, href }, or null to cancel, also as a promise.
<MarkdownEditor
label="Notes"
toolbar={['bold', 'italic', 'link']}
pickLink={({ selectedText }) => pickDocument(selectedText)}
/>
Customize
The editor's root is env-markdown-editor, with the tabs, env-tabs-list, the toolbar, a Toolbar in env-editor-toolbar, the source, env-markdown-editor-input, and the description, env-field-description.
classNameandstylereach the root, andrefand the other native props the textarea.- A rendered document is
env-markdown, withenv-prose, and a table in it scrolls inenv-markdown-table. - Lists in it take envUI's list markers: a small spark, four points with curved sides, in the text color, or the item's number in the muted text color, with a smaller muted spark or a letter one level in.
Accessibility
You provide
- A
labelfor MarkdownEditor. - Link text that names its destination.
- Translated words through EnvUIProvider's
messages.
envUI provides
- Native headings, lists, quotes, tables and links.
- Tables in focusable, scrolling regions named after their caption or heading.
- Task items as read-only checkboxes.
- A native textarea tied to its label, a named toolbar and named tabs.
Props
Markdown
CommonMark prose with tables, task lists and other extensions, in envUI typography and code. The names of its table regions and task checkboxes come from EnvUIProvider's messages.markdown.
| Prop | Type | Description |
|---|---|---|
childrenrequired | string | The Markdown string to render. |
headingOffsetDefault 0 | 012345 | Add to the document's heading levels; levels are capped at h6. |
renderLink | ( | Receives safe hrefs and native anchor props. Retain a real anchor destination. |
codeCopyableDefault false | boolean | Gives each code block a copy button; false by default. |
components | Components | react-markdown component overrides, merged over envUI's own; the application's win. Native props such as id and className reach the element. |
remarkPlugins | Options[ | remark plugins that run after envUI's own Markdown extensions. |
rehypePlugins | Options[ | rehype plugins, such as heading ids; envUI adds none of its own. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
MarkdownEditor
Native Markdown source editing, shared formatting history, and optional preview. Its toolbar, views and status come from EnvUIProvider's messages: markdownEditor, editor and linkDialog.
| Prop | Type | Description |
|---|---|---|
ref | Ref< | The native text area of the source, so that a form library can register it and focus it. |
value | string | The Markdown source of a controlled editor; replacing it clears the undo history. |
defaultValueDefault '' | string | The source an uncontrolled editor starts with, and that a form reset restores. |
onValueChange | ( | Receives the whole source after typing, formatting, undo or redo. |
toolbarDefault ['heading', 'bold', 'italic', 'inline-code', 'bullet-list', 'numbered-list', 'quote', 'code-block', 'link'] | readonly MarkdownCommand[false | Formatting actions; false hides the toolbar. Undo/redo accompany a visible toolbar. |
previewDefault true | boolean | Show Write/Preview tabs. Preview uses the same public Markdown renderer. |
previewProps | Pick< | Options of the Markdown that renders the preview: headingOffset, renderLink and codeCopyable. |
pickLink | ( | Optional application picker. Return null to cancel; otherwise return an ordinary link. |
label | ReactNode | The field's visible name, such as Project name; it also names the control for assistive technology. |
style | CSSProperties | Styles of the field's root element, such as its width in a row. |
className | string | The field's class, on its root element, beside env-field, env-text-field and env-textarea. |
description | ReactNode | Lasting guidance under the field, such as a format or a limit, linked to the control as its description. |
rowsDefault 8 | number | The lines the field shows: with fixed sizing, its height in rows, which resizes down to them or to 7.5 rem, whichever is less; with content sizing, the lines it starts at and shrinks back to. Without rows, both start at 7.5 rem. |
variantDefault 'outline' | 'outline''ghost' | The field's look, as TextField's: outline or ghost. A text area is always tall, with its label resting at the top. |
error | ReactNode | A message under the field that says how to correct the value. While it is set, the control is invalid (aria-invalid) and the message joins its description, after the description. |
sizingDefault 'fixed' | 'fixed''content' | How the height follows the text: fixed keeps its height, scrolls and resizes from the bottom edge, by dragging it or with the arrow keys; content grows and shrinks with the text. |
Also accepts the native props of <textarea>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
Markdown
env-markdown- The rendered Markdown.
env-markdown-table- The region that scrolls a wide table.
MarkdownEditor
env-markdown-editor- The Markdown editor.
env-markdown-editor-input- The text area that shows the Markdown source as text.
env-markdown-editor-write- The text area for writing.
Strings
EnvUIProvider's messages overrides each, and a component's own label prop wins over it.
messages.editor.heading"Heading"A command.messages.editor.bold"Bold"A command.messages.editor.italic"Italic"A command.messages.editor.strike"Strikethrough"A command.messages.editor.bulletList"Bulleted list"A command.messages.editor.numberedList"Numbered list"A command.messages.editor.taskList"Task list"A command.messages.editor.quote"Quote"A command.messages.editor.inlineCode"Inline code"A command.messages.editor.codeBlock"Code block"A command.messages.editor.link"Insert link"A command.messages.editor.table"Insert table"A command.messages.editor.undo"Undo"A command.messages.editor.redo"Redo"A command.messages.linkDialog.title"Insert link"The dialog's title.messages.linkDialog.insert"Insert link"The confirm button's label.messages.linkDialog.text"Text"The text field's label.messages.linkDialog.url"URL or path"The URL field's label.messages.linkDialog.urlPlaceholder"https://example.com or /documents/example"The URL field's placeholder, an example of what it takes.messages.linkDialog.invalidUrl"Enter a valid URL."The error for an empty destination.messages.linkDialog.invalidPath"Enter a valid URL or relative path."The error for a destination that is neither a URL nor a path.messages.markdown.table"Table"Names a table region without a caption, a heading or a header row.messages.markdown.tableNamed({ name }) => stringNames a table region after the heading before it, such as Prices table, or without one, after its first column's header.messages.markdown.taskDone"Completed task"A completed task's checkbox.messages.markdown.taskOpen"Incomplete task"An incomplete task's checkbox.messages.markdownEditor.empty"Nothing to preview."The preview of an empty document.messages.markdownEditor.toolbar"Markdown formatting"Names the formatting toolbar.messages.markdownEditor.views"Markdown editor views"Names the write and preview tabs.messages.markdownEditor.write"Write"The write tab.messages.markdownEditor.preview"Preview"The preview tab.messages.markdownEditor.changedWhilePicking"The text changed while the picker was open. Insert the link again."Said when the text changed while the application's link picker was open.messages.markdownEditor.tooLong"This change would exceed the maximum length, or editing is unavailable."Said when a link would make the text too long, or editing is unavailable.messages.markdownEditor.tooLongShort"This change would exceed the maximum length."Said when a formatting command would make the text too long.messages.markdownEditor.linkFailed"The link could not be inserted."Said when the link could not be inserted.messages.markdownEditor.pickerFailed"The link picker could not finish. Try again."Said when the application's link picker failed.
Changelog
- 1.0.0
Code in Markdown takes the new code themes, as Code and CodeBlock do. MarkdownEditor takes Textarea's
descriptioninstead ofhint, and its variantsoutlineandghost:outlinedisoutlineandquietisghost, andplainis gone, for the default outline.classNameandstylestyle the root,env-markdown-editor, rather than the textarea;refand the other native props still reach the textarea. Its toolbar is a Toolbar, with tooltips instead of native titles, and its words come from EnvUIProvider'smessages, as do Markdown's table and task names. Markdown's root carriesenv-prosebesideenv-markdown. Markdown is stable; MarkdownEditor stays beta. The editor's source text area,env-markdown-source, isenv-markdown-editor-input, a MarkdownEditor part asenv-text-field-inputis a TextField's.- 1.0.0-prerelease.6
Bold text is semibold rather than medium, so it stands out from the body text around it; it is heavier than a heading's medium, which its size sets apart.
Where MarkdownEditor's toolbar is wider than the editor, its groups wrap onto more rows rather than scrolling sideways, so Undo and Redo stay in view. The editor's label takes the size, weight and muted color of a field's floated label.
A table's header cells line up at the start, over their columns' text, rather than in the middle.
- 1.0.0-prerelease.5
onRequestLinkispickLink: it supplies the link rather than reporting an event.- 1.0.0-prerelease.2
MarkdownEditor's
underlinevariant, whichplainbecame in the earlier prereleases, is gone, for the default outline.