A lightweight, accessible before/after image comparison slider for Svelte 5.
ResizeObserver-based sizing — no stale layout bugsoffset prop$effect)npm i svelte-before-after
<script>
import { BeforeAfter } from 'svelte-before-after';
</script>
<BeforeAfter before="/before.jpg" after="/after.jpg" />
| Prop | Type | Default | Description |
|---|---|---|---|
before |
string |
required | URL of the "before" image |
after |
string |
required | URL of the "after" image |
offset |
number |
0.5 |
Split position (0–1). Bindable. |
contain |
boolean |
false |
If true, fills parent width/height |
overlay |
boolean |
true |
Dark overlay on hover |
hideOnSlide |
boolean |
true |
Fade labels/overlay while dragging |
beforeLabel |
Snippet |
— | Snippet for the before label |
afterLabel |
Snippet |
— | Snippet for the after label |
vertical |
boolean |
false |
Top-to-bottom slider mode |
handleSize |
number |
40 |
Drag handle diameter in px |
class |
string |
"" |
Additional CSS class on container |
Use Svelte 5 snippets to add custom label content:
<BeforeAfter before="/before.jpg" after="/after.jpg">
{#snippet beforeLabel()}
<span class="badge">Before</span>
{/snippet}
{#snippet afterLabel()}
<span class="badge">After</span>
{/snippet}
</BeforeAfter>
The offset prop supports bind::
<script>
import { BeforeAfter } from 'svelte-before-after';
let offset = $state(0.5);
</script>
<BeforeAfter before="/before.jpg" after="/after.jpg" bind:offset />
<input type="range" min="0" max="1" step="0.01" bind:value={offset} />
<BeforeAfter before="/before.jpg" after="/after.jpg" vertical={true} />
Style the component using CSS custom properties on a parent or the component itself:
| Property | Default | Description |
|---|---|---|
--handle-color |
white |
Handle border & divider color |
--handle-size |
40px |
Handle diameter |
--overlay-color |
rgba(0,0,0,0.5) |
Hover overlay color |
--transition-duration |
0.35s |
Transition speed for overlay/labels |
<div style="--handle-color: yellow; --overlay-color: rgba(0,0,0,0.3);">
<BeforeAfter before="/before.jpg" after="/after.jpg" />
</div>
When the component is focused:
| Key | Action |
|---|---|
ArrowLeft / ArrowUp |
Decrease offset by 1% |
ArrowRight / ArrowDown |
Increase offset by 1% |
The component renders with the following ARIA attributes:
role="slider" — identifies it as a slider controlaria-valuemin="0" / aria-valuemax="100" — range boundariesaria-valuenow — current percentage (0–100)aria-label — descriptive labeltabindex="0" — keyboard focusableThis component is fully SSR-safe. All browser APIs (ResizeObserver, getBoundingClientRect, window event listeners) are used inside $effect blocks, which only execute client-side.