The editor

One Markdown file, three ways to look at it, and one insert menu that behaves identically in all of them.

The three views

The view is stored per note, so a README can stay in Source while your meeting notes stay in Rich. Switch with the Rich / Split / Source control in the header.

Rich

A block editor. Headings, lists, tables, checkboxes and diagrams render as you type. Markdown shorthand works: # makes a heading, - a bullet, > a quote. Selecting text pops a small formatting bar.

Split

CodeMirror on the left with the raw Markdown, a live preview on the right. Drag the divider, or focus it and use the arrow keys. This is the view to use when you want to see exactly what will be committed.

Source

The same CodeMirror editor, full width, centred at a readable measure. Syntax highlighting, line numbers, code folding, bracket matching and search.

Switching views never reformats the file. All three read and write the same Markdown string — no round-tripping through a proprietary document model, no surprise whitespace changes in your diff.

The formatting bar

Above every view is a bar carrying everything Markdown can express: undo and redo, a paragraph-style dropdown for headings, quotes and code blocks, the five inline marks, the three kinds of list with indent and outdent, links, images, tables, dividers and diagrams. Anything that does not fit has a More menu.

The bar drives whichever view is open. In Rich it runs an editor command; in Split and Source it edits the Markdown itself — select a word and press B and it is wrapped in **, choose Heading 2 and the line gains a ## rather than a second one being pasted over the first.

There are no fonts, colours or alignment controls, because none of those survive being written to a .md file. A button that quietly did nothing to the saved document would be worse than no button.

While the caret is inside a table, a second row of controls appears for adding and removing rows and columns, toggling the header row and merging cells.

The insert menu

Press / anywhere, or use the toolbar. Both give the same list, and it works in every view — in Rich it runs an editor command, in Split and Source it inserts the equivalent Markdown at your caret.

ItemRich textMarkdown inserted
DiagramA live diagram block```mermaid
Heading 1 / 2 / 3Heading node#
TextPlain paragraph—
Bulleted listBullet list-
Numbered listOrdered list1.
To-do listCheckbox list- [ ]
Code blockFenced code node```
QuoteBlockquote>
Table3×3 with a header rowPipe table
DividerHorizontal rule---
LinkAsks for the text and the address[](…)
ImageOpens the image picker![](…)
YouTube videoAsks for the video's addresshttps://youtu.be/…

Search as you type: /erd, /flowchart and /gantt all find Diagram; /todo finds the checkbox list. Arrow keys move, Enter accepts, Escape dismisses.

Links accept http://, https://, mailto: and paths within the repository only. A javascript: URL in a note would be a stored cross-site-scripting vector in every renderer that later displays it, so those are rejected.

Images

Paste a screenshot straight into a note, drag a file onto it, or use the Image button — all three work in Rich, Split and Source. PNG, JPEG, GIF, WebP, AVIF, BMP and ICO are accepted, up to 3 MB each. SVG is not: it is a document format that can carry script, and serving one back would be a hole in every note that embeds it.

On a connected repository the file is committed to an assets/ folder as its own commit, and the note links to it by a relative path — ../assets/2026-08-22-chart.png — exactly as a hand-written Markdown file would. That is what keeps the note rendering correctly on github.com, in an IDE, or anywhere else the repository is opened. ForkLeaf resolves the path back through its own server when it displays the note, so images in a private repository load without the file ever being public.

With no repository connected there is nowhere to commit a file, so the bytes are kept on this device instead. The note still links to the same relative path it would use in a repository, so the markdown reads the same either way — connecting a repository later is all it takes for the images to travel with the notes.

You can also link to an image already on the web. Those are stored as the URL you give, untouched.

Moving a note takes its images with it. The link in the file is relative to where the note sits — that is what makes it work on github.com — so ForkLeaf rewrites those links as part of the move; the image files themselves stay where they are, since other notes may be using them.

A note written elsewhere — or moved by an older version of ForkLeaf — can point at image paths that hold nothing, and every picture in it shows as a broken box. Opening such a note repairs it: ForkLeaf looks for the files by name, repoints the ones it can identify with certainty, and says how many it moved. Nothing that already works is touched, and a name that matches two different files is left alone rather than guessed at.

YouTube videos

Put a YouTube link on a line of its own — paste it into an empty line, or use the YouTube video item in the / menu — and Rich view and the preview show the player. Watch links, youtu.be short links, Shorts and live URLs are all understood, and a ?t= start time is kept.

Nothing unusual is written to the file: the note holds the plain Markdown link and nothing else, so it reads as a link on github.com, in an IDE and in every other Markdown tool. A link inside a sentence stays a link — only a line that is nothing but the link becomes a player — which leaves you a way to mention a video without embedding it.

The player is loaded from youtube-nocookie.com, so opening a note that contains a video does not drop tracking cookies on whoever is reading it.

Inline formatting

In Rich view, select text to get bold, italic, strikethrough, inline code and highlight — or use the toolbar, or ⌘B and ⌘I. In Split and Source, the same toolbar buttons wrap the selection in the equivalent Markdown, and you can of course type it yourself.

Highlighting writes ==like this==, the convention Markdown note-taking tools have settled on. ForkLeaf renders it; github.com does not, and shows the equals signs.

Notes, folders and names

  • Every note is one .md file. The title you type becomes a slugified filename — Q3 planning becomes q3-planning.md.
  • Folders are real directories, nested as deeply as you like. The folder button beside New Note makes one at the top level; hovering a folder row gives you a note, a subfolder, a rename and a delete for that folder.
  • A folder you have just made shows as Empty and lives on this device only, because Git has no concept of an empty directory — it becomes part of the repository as soon as its first note lands in it. Renaming or deleting a folder moves or deletes every note inside it, which is what those words mean in a repository.
  • Renaming rewrites the path. On a connected repository that is a delete and a create in one atomic commit, so the file never briefly disappears.
  • Deleting commits the deletion. The content is still in your git history, so it is recoverable — see Syncing & commits.

The search box above the file tree filters by path and name as you type. Inside the Source view, ⌘F opens CodeMirror’s find-and-replace for the current note.

Full-text search across every note in every connected repository is planned for Pro — see Plans & billing.