WebDev Bites: ViewComparator Component Demo

two-panel viewer with draggable splitter, bottom resizer, and right-panel offset

function greet(name) {
  return `Hello, ${name}!`;
}

const nums = [3, 1, 4, 1, 5, 9];
nums.sort((a, b) => a - b);
console.log(nums.join(', '));

function square(x) {
  return x * x;
}
def greet(name):
    return f"Hello, {name}!"

nums = [3, 1, 4, 1, 5, 9]
nums.sort()
print(', '.join(map(str, nums)))

def square(x):
    return x * x
This is a view-comparator component. Drag the vertical bar to redistribute width between panels. Drag the strip at the bottom edge to change the component height. Click either panel to shift the split by one step. Use the small ▲ / 0 / ▼ buttons that appear in the top-right corner of the right panel to shift that panel's content up or down for line-by-line alignment; keyboard shortcuts Alt+↑, Alt+↓, and Esc also work when the right panel has focus.
This is the first in a sequence of pages that explore the design of a W3C web component that manages a resizable two-panel view with a draggable splitter and a vertical offset control for code comparison. The next page explains the design of the component. The final page shows how an application uses the viewer and lists its public interface.

Component Parts

The primary parts of a web component are:
  1. Class derived from HTMLElement
    Each application of the component's tag creates an instance of this class when the code is parsed at load time.
  2. Shadow DOM, a tree of encapsulated HTML elements
    ViewComparator separates its shadow DOM into two module-level template strings: VC_STYLE for the CSS and VC_TEMPLATE for the HTML structure.
    The shadow DOM defines a .container flex row holding .panel-left, a .splitter bar, and .panel-right, plus a .resizer strip below the container for height adjustment. The right panel also hosts an .offset-controls overlay with three small buttons for shifting content vertically.
    Each panel exposes a named slot (slot="left" and slot="right") so the host page supplies content as slotted <pre> or <pre><code> elements.
  3. Event listeners
    Four sets of listeners handle interaction. Splitter drag: mousedown on the splitter bar, then mousemove/mouseup on the document. Resizer drag: mousedown on the resizer strip, then mousemove/mouseup on the document. Panel click: a click on either panel shifts the split by one step-px increment. Offset controls: click on ▲/▼ to shift right-panel content by offset-step-px; click 0 to reset; Alt+Arrow keys and Esc work when the right panel has focus.
    A slotchange listener on each slot applies Prism highlighting and normalizes the box model of newly assigned <pre> elements, then scrolls both panels to the top.
    A ResizeObserver on the host element re-applies the current split ratio whenever the host changes width, keeping the panels correctly proportioned during page resizes.
  4. Helper functions
    ViewComparator uses _getLeftPx(), _setLeftPx(), _availableWidth(), _totalWidthPx(), _getHeightPx(), _setHeightPx(), _applyStyles(), _applyLayout(), _maybePrism(), _harmonizeSlotted(), _adjustOffset(), _setRightOffset(), _applyRightPaddingTop(), and _handleOffsetKey().
  5. Hyphenated tag name associated with the component class.
    The tag name view-comparator is associated with the class ViewComparator.