comparison-wc

Before/after image comparison slider with drag handle, keyboard support, and progressive enhancement.

Overview

The <comparison-wc> component creates a before/after comparison slider. Two children overlay each other, and a draggable divider reveals one side. Works with any two children — images, divs, or any other elements.

<comparison-wc> <img src="before.jpg" alt="Before" /> <img src="after.jpg" alt="After" /> </comparison-wc>

Attributes

Attribute Type Default Description
data-position number 50 Initial slider position from 0 (fully left) to 100 (fully right).

Custom Start Position

Set data-position to control where the divider starts. A value of 25 means the divider starts 25% from the left, showing mostly the “after” content.

Before
After
<!-- Start at 25% --> <comparison-wc data-position="25"> <img src="before.jpg" alt="Before" /> <img src="after.jpg" alt="After" /> </comparison-wc>

Non-Image Content

The component works with any two child elements, not just images. Use divs, text blocks, or any HTML content.

Draft

The original version before revisions.

Final

The polished version with improved clarity.

<comparison-wc> <div class="panel-before">Draft version</div> <div class="panel-after">Final version</div> </comparison-wc>

Keyboard Navigation

Key Action
ArrowLeft / ArrowDown Move divider 1% left
ArrowRight / ArrowUp Move divider 1% right
Shift + Arrow Move divider 10% in the arrow direction

Events

Event Detail Description
comparison-change { position: number } Fired when the slider position changes (drag or keyboard).
const slider = document.querySelector('comparison-wc'); slider.addEventListener('comparison-change', (event) => { console.log('Position:', event.detail.position); });

Accessibility

Slider Role

The divider has role="slider" with aria-valuemin, aria-valuemax, and aria-valuenow. Screen readers announce position changes as the slider moves.

Keyboard Support

The divider is focusable (tabindex="0") and responds to arrow keys. Shift + arrow provides larger steps for faster navigation.

Touch Support

The divider uses touch-action: none and setPointerCapture for reliable touch/pointer drag behavior across devices.

Styling

The divider and handle can be styled with CSS. The divider is a .comparison-divider element with a ::after pseudo-element for the circular handle.

/* Custom divider color */ .comparison-divider { background: var(--color-interactive); } /* Custom handle */ .comparison-divider::after { background: var(--color-interactive); border-color: white; }

Progressive Enhancement

Without JavaScript, both children display side-by-side in a natural grid. The :not(:defined) selector provides the fallback layout. Once JS registers the component, children overlap and the clip-path slider takes over.

/* Without JS: side-by-side grid */ comparison-wc:not(:defined) { display: grid; grid-template-columns: 1fr 1fr; gap: var(--size-s); }

Related Elements