I added a small task box to a settings panel. Three rows, a placeholder, nothing unusual. It rendered as an enormous empty rectangle covering the entire card, hiding every control above and below it.

The cause was a rule written months earlier, for something else entirely, and it was doing exactly what it was told.

How a highlighted editor is built

Browsers cannot colour text inside a <textarea>. So a syntax-highlighted editor is almost always two layers: a <pre> underneath holding coloured markup, and a transparent textarea stretched exactly over it catching the typing. Scroll them together and it looks like one thing.

The CSS for the top layer looks like this:

textarea {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  color: transparent;
  caret-color: #fff;
  white-space: pre;
  resize: none;
}

Every line is right — for the editor. The problem is the selector.

A bare element selector has no scope

textarea matches every textarea in the document, forever, including ones nobody has written yet. So my task box was absolutely positioned at the top-left of its container, stretched to the full height of it, with transparent text.

It was not broken. It was behaving exactly as a code editor should, in a place that was not a code editor.

The transparent text is the part that makes this hard to diagnose. An oversized box is obvious. An oversized box with invisible text reads as "nothing rendered", so you go looking for a JavaScript error that does not exist.

The tell

There was already a fix for this in the same stylesheet, written for a dialog that had hit the same wall earlier:

.github-dialog textarea {
  position: static;
  inset: auto;
  height: auto;
  min-height: 110px;
  white-space: pre-wrap;
  resize: vertical;
}

When a codebase contains a rule whose only job is to undo another rule, that is a signal. Not a bug on its own — but the second time somebody writes one of those, the original selector is too broad and everyone is paying for it.

Scope it to the thing it describes

The fix is one word. The rule belongs to the editor, so say so:

#activeEditor {
  position: absolute;
  /* ... */
}

Now a textarea is a textarea unless it is that one. No undo rules, nothing to remember, and the next person to add a form does not lose an afternoon.

Where else this hides

The pattern is always the same: a bare element selector carrying rules that describe a specific component rather than the element in general. The usual suspects:

  • input { } with the search box's padding in it.
  • button { } set to the primary action's colour.
  • pre { } with the code viewer's fixed height.
  • table { } laid out for one particular table.

A reset in a bare element selector is fine — that is what resets are for. A component in one is a trap with a long fuse. It will not go off until somebody adds an ordinary version of that element months later, and by then nobody remembers the rule exists.

Worth grepping for. It takes a minute and there is usually at least one.