Editing


Enter continues a list or a blockquote onto the next line, and ends it on an empty item. The formatting shortcuts are in The toolbar.

What Enter does #

With New Paragraph on Enter on, Enter leaves a blank line behind it and ⇧Enter gives the single newline. That's the division every rich text editor makes.

It's off by default, because a field whose authors write Markdown doesn't need it. Turn it on for one whose authors don't. A single newline is the one piece of Markdown that does nothing you can see: a <br> with Preserve Line Breaks on, and with it off a space, so the two lines you just separated come back as one. Neither is a paragraph, and "press it twice" is not something anyone arrives already knowing.

Enter keeps its other jobs either way, carrying on a list or a quote and ending one on an empty item. A blank line already under the caret isn't doubled, so holding Enter down leaves a gap rather than a pile of them.

It sits with Preserve Line Breaks and Inline Only because the three are one question: what a line break means in this field. It disappears when Inline Only is on, and is ignored there, since a field rendering without a <p> has no use for a key that starts one.

⌘⇧P swaps between Write and Preview, from anywhere in the field, and puts the caret back where it was on the way in. It does nothing on a field with Show Preview Tab off, or while there’s nothing written to preview.

The editor grows as the author types, between Minimum Rows and Maximum Rows. Dragging the resize handle takes over from there. Once someone has picked a height by hand, it stops resizing itself.

The header #

Once a field fills more than half the window, its header sticks. The tabs and the toolbar hold still and the text scrolls under them, so the buttons are still there when the writing has run past where they were. That’s measured on the Write tab whichever tab is up, because rendered Markdown is shorter than its source, and a header that came and went as you switched would be worse than one that never held still.

Below that they scroll away with everything else. A short field is gone almost as soon as its header is, so sticking it would only slide the strip over the last few rows on the way past.

It stops below Craft’s own page header, which pins itself to the top of the window once the page scrolls. Craft has no token for that height and it isn’t a fixed number, so the editor measures it. In a slideout, a modal, or anywhere else scrolling in a box of its own it’s zero, since the field’s header already stops below that thing’s chrome.

There’s no setting for it and no threshold to tune. If your control panel has put something else along the top, --wahlberg-sticky-top on .wahlberg overrules the measurement.

Keeping your place #

Switching between Write and Preview halfway down a long field puts you back where you were, rather than at the top.

What’s matched is structure, not distance. The two panes hold the same content at wildly different lengths, since a link is a URL’s worth of source and a word of rendered text, and a reference tag is worse. A percentage or a pixel offset would land somewhere arbitrary. So the source is split into the blocks the parser turns into elements, and the block at the top of one pane is the element put at the top of the other.

Blocks and elements come out one for one nearly always. Where they don’t, as when a list with blank lines between its items is several blocks of source and a single <ul>, the position is scaled rather than trusted, landing in the right region instead of on the wrong paragraph. At the top of a field, switching does nothing at all.

The current line #

The line being written carries a band behind it, the way a code editor does. A long line wraps over several rows and the band covers all of them, since what it marks is the line the author is on rather than the row the caret is in. In Markdown that block is usually the paragraph.

It’s up only while the field has focus and nothing is selected. A selection already says where the author is, and a page of fields each wearing a band says nothing at all.

In light mode it’s --gray-050, the same step on Craft’s ramp the field’s header sits on. In dark it’s a 3% lift off whatever the surface is. Nothing else about the field’s colours changes.

There’s no setting for it. Retheme or switch it off with the CSS variables on .wahlberg:

Variable Default
--wahlberg-active-line --gray-050, or a 3% lift in dark mode transparent to do without
--wahlberg-active-line-pad 1px how far the band stands proud of the row, top and bottom
--wahlberg-line-height 1.6 the row itself, which the caret and the selection are drawn to as well
--wahlberg-measure 48em how wide the text runs under Line Length, about 80 characters

Both text layers take the last two from the same place on purpose: wrapping in different places, or sitting on different line heights, is the one mismatch the editor can’t measure its way out of. That’s why --wahlberg-measure is in em and not the ch a monospace column asks for. ch is the width of a 0 in the face the browser resolved, and the two layers don’t always resolve the same one.

Reach for --wahlberg-line-height if the caret looks too tall for the text. A browser draws it to the full row, so the only way to shorten it is to tighten the row.

Syntax highlighting #

The Write tab highlights Markdown as you type and is still a plain <textarea>. The colour comes from a layer rendered behind it, with the textarea’s own text made transparent, so native undo, spellcheck, selection and form submission all behave as they otherwise would.

Bold and italic are used only where the font family has real cuts for them. The editor measures on load and falls back to colour alone where a fabricated cut would advance wider and pull the two layers apart. Nothing is lost by that, since in Markdown source the ** and _ are on screen anyway.

Retheme with the CSS variables on .wahlberg: --wahlberg-mark, --wahlberg-heading, --wahlberg-strong, --wahlberg-em, --wahlberg-code, --wahlberg-link, --wahlberg-url, --wahlberg-quote. Keep to colour, since setting weight or slope here goes around that measurement. Each defaults to a step on Craft’s own ramp rather than a fixed hex, so a control panel theme that redeclares the palette, dark mode included, moves the editor with it.

If the two layers ever look out of step, add the wahlberg--debug class to the field to paint the textarea’s own text in red over the layer beneath it.