Renderer
InkwellRenderer converts a Markdown source string into React elements. It
produces semantic HTML, has no browser dependencies, and works in any
React environment including server-side rendering.
import { InkwellRenderer } from "@railway/inkwell";
<InkwellRenderer content="# Hello **world**" />;The renderer handles CommonMark plus GitHub Flavored Markdown features such
as strikethrough, task lists, and autolinks. GFM table syntax is
intentionally rendered as source text; Inkwell does not emit <table>
elements by default.
Custom components
Section titled “Custom components”Override how specific HTML elements render using the components prop.
Each component receives the original element’s props and children.
<InkwellRenderer content={content} components={{ a: ({ children, ...props }) => ( <a {...props} target="_blank" rel="noopener noreferrer"> {children} </a> ), pre: ({ children, ...props }) => ( <pre {...props} className="my-code-block"> {children} </pre> ), img: ({ alt, ...props }) => ( <figure> <img {...props} alt={alt} loading="lazy" /> {alt && <figcaption>{alt}</figcaption>} </figure> ), }}/>You can override any HTML element: h1–h6, p, a, img,
blockquote, pre, code, ul, ol, li, strong, em, del,
and more.
Syntax highlighting
Section titled “Syntax highlighting”Code blocks are highlighted with highlight.js by default. Import a theme CSS file for colors to appear:
import "highlight.js/styles/github-dark.css";To use a different highlighter, pass it through rehypePlugins:
import rehypeShiki from "@shikijs/rehype";
<InkwellRenderer content={content} rehypePlugins={[[rehypeShiki, { theme: "github-dark" }]]}/>;The same rehypePlugins option is available in
InkwellEditor.
Props reference
Section titled “Props reference”content
Section titled “content”Type: string
The Markdown source string to render.
components
Section titled “components”Type: InkwellComponents
A map of HTML element names to React components. See Custom components.
rehypePlugins
Section titled “rehypePlugins”Type: RehypePluginConfig[]
Custom rehype plugins for the Markdown rendering pipeline. Accepts a
plugin function or a tuple such as [plugin, ...options].
Fenced code blocks include a copy button. Hover over a code block to reveal the button.
softBreak
Section titled “softBreak”Type: "preserve" | "br" | "paragraph"
Default: "paragraph"
How single-newline soft breaks in source markdown render.
CommonMark treats a single newline inside a paragraph as a “soft break”. Strict
CommonMark output keeps that as a literal \n text node, which the browser
collapses to a space — most users find this surprising. Inkwell defaults to
"paragraph", which splits the source at the soft break so each line becomes
its own paragraph. For this source:
Best Regards,Your Name| Value | Output | Visual |
|---|---|---|
"paragraph" (default) | <p>Best Regards,</p><p>Your Name</p> | two paragraphs with normal margins |
"br" | <p>Best Regards,<br />Your Name</p> | two adjacent lines |
"preserve" | <p>Best Regards,\nYour Name</p> | one line (strict CommonMark) |
<InkwellRenderer content={md} softBreak="br" />The transformation happens at the markdown AST level, so the rendered output
contains real <p> (or <br />) elements you can style normally. Only
paragraph nodes are touched: code fences keep their internal newlines intact,
and list items and blockquotes don’t split — a list item whose paragraph has
a soft break ends up as one <li> containing two <p> siblings.
Hard breaks (two trailing spaces, the standard CommonMark hard-break syntax)
always render as <br /> regardless of this setting.
mentions
Section titled “mentions”Type: MentionRenderer[]
Text patterns to hydrate into custom React nodes during rendering. Each
entry provides a pattern regular expression and resolve(match) callback;
matches are replaced in rendered text. This is useful for persisted markers
inserted by the mentions plugin.
className
Section titled “className”Type: string
CSS class applied to the wrapper <div>.
Utilities
Section titled “Utilities”Use the renderer utilities when you need the same parsing or HTML conversion
without rendering <InkwellRenderer /> directly.
import { htmlToMarkdown, parseMarkdown } from "@railway/inkwell";
const previewNodes = parseMarkdown(content, { components, rehypePlugins: [[rehypeShiki, { theme: "github-dark" }]], mentions,});const markdown = htmlToMarkdown(html);parseMarkdown(content, options)
Section titled “parseMarkdown(content, options)”Parses Markdown source into React nodes using the same component overrides,
rehype plugin pipeline, and mention hydration options as InkwellRenderer.
htmlToMarkdown(html)
Section titled “htmlToMarkdown(html)”Converts an HTML string into Markdown source.