- ds
- Components
- Code editor
Code editor
A mono textarea with line numbers, error lines and a problems list.
- 2 problems
Show code
<div class="editor" style="height:15rem">
<div class="editor-gutter" aria-hidden="true">
<span>1</span><span>2</span>…<span class="err">5</span><span>6</span><span class="warn">7</span>
</div>
<div class="editor-area">
<div class="editor-marks" aria-hidden="true">
<i class="err" style="--line:5"></i><i class="warn" style="--line:7"></i>
</div>
<textarea class="editor-input" wrap="off" spellcheck="false" aria-label="Crontab">…</textarea>
</div>
<ul class="editor-errors" aria-label="Problems">
<li class="label">2 problems</li>
<li><button class="editor-err" type="button"><code>5:8</code><span>Hour 25 is out of range (0–23)</span></button></li>
<li><button class="editor-err warn" type="button"><code>7:21</code><span>No command after the schedule</span></button></li>
</ul>
</div>The surface lab and ack use for text input: a mono textarea with line numbers, line highlights for errors and warnings, and the problems listed under the text. This one checks a crontab as you type. Fix the hour on line 5, or click a problem to jump to it.
It is styling only. Tokenising, highlighting and validation belong to the product, and so does the script that keeps the three layers in step. What ds.css guarantees is that they line up: the gutter, the marks and the text share one line height and one top padding, in rem, at every root size.
Keeping the layers in step
// Scroll: the gutter and the marks follow the textarea.
input.addEventListener('scroll', () => editor.style.setProperty('--scroll', input.scrollTop));
// After each edit: one gutter row per line, one mark per line with a problem.
gutter.innerHTML = lines.map((_, i) => `<span class="${sev(i + 1)}">${i + 1}</span>`).join('');
marks.innerHTML = problems.map((p) => `<i class="${p.sev}" style="--line:${p.line}"></i>`).join('');The textarea does not wrap (white-space: pre, plus wrap="off" for Safari), so line n is always row n and the numbers never drift. Long lines scroll sideways.
API
| Class | On | What it does |
|---|---|---|
.editor | div | The frame: gutter, text and problems. Give it a height, or set rows on the textarea. |
--lh / --pad | .editor | Line height (1.375rem) and top padding (0.625rem), shared by all three layers. |
--scroll | .editor | The textarea's scrollTop, unitless. The gutter and marks move with it. |
.editor-gutter | div | Line numbers, one span per line. .on for the caret line, .err and .warn. |
.editor-area | div | Holds the marks and the textarea. |
.editor-marks | div | Highlights under the text: <i class="err" style="--line:5">. Also .warn and .on. |
.editor-input | textarea | Mono, no wrapping, transparent so the marks show through, accent caret. |
.editor-errors | ul | Problems under the text. Hidden when empty. A li.label can head it. |
.editor-err | button | One problem: a dot, the position in <code>, the message. .warn for a warning. |
Accessibility
- The gutter and marks are
aria-hidden. Pointaria-describedbyfrom the textarea at the problems list, so the count and messages are reachable. - Each problem is a button that moves the caret to its line and column.
- Tab types a tab in most code editors. If you do that, leave Escape then Tab as the way out, and say so near the editor.