Before and after comparison with a draggable divider, for scan cleanup previews. The before layer is clipped to ratio of the width; the orange handle drags with the pointer and is a keyboard slider. Pass two sources, or one source with beforeFilter to fake the before from the after.
import { Component } from "@angular/core";
import { SuiImageCompare } from "@shineui/angular";
@Component({
standalone: true,
imports: [SuiImageCompare],
template: `<sui-image-compare before-src="/docs/assets/imagery/nonprofits.webp" after-src="/docs/assets/imagery/nonprofits.webp" before-filter="grayscale(1) contrast(0.75) brightness(1.05)" before-label="Original" after-label="Enhanced" (suiError)="onChange($event)"></sui-image-compare>`,
})
export class Example {
onChange(e: CustomEvent) { console.log(e.detail); }
}
Basic
One source plus before-filter fakes the before from the after, the common shape for an enhancement preview. The frame fills its container; height sets the rest.
// setup(root): properties and events
setup(root) {
const el = root.querySelector('#cmp-two');
el.beforeAlt = 'A hard hat resting on rolled plans at a building site';
el.afterAlt = 'An aerial view of a finished suburban street lined with houses and lawns';
}
Controlled ratio and events
ratio is mutable and clamped to 0.04..0.96. suiResize fires while the divider moves and suiResizeEnd when it lands, the pair sui-splitter uses for its ratio; wire expensive work to suiResizeEnd. Neither bubbles.
With either picture lost there is nothing to compare, so the frame shows the image glyph and a quiet line on its well and drops the divider and the labels. suiError fires once per failed source with that source.
Moves focus to the handle, a slider whose value is the before share of the width. A pointer press anywhere on the frame moves the divider there and focuses the handle.
ArrowRightArrowUp
Move the divider right by 2%, showing more of the before layer.
ArrowLeftArrowDown
Move the divider left by 2%.
PageUpPageDown
Move the divider right or left by 10%.
HomeEnd
Jump the divider to the far left or the far right; travel stops at 4% and 96% so the handle stays on the frame.
API
<sui-image-compare>
Properties
Property
Attribute
Type
Default
Description
afterAlt
after-alt
string
''
Alt text for the after layer. Empty (the default) leaves it decorative.
afterLabel
after-label
stringstring | undefined
Uppercase tag at the top right.
afterSrc
after-src
stringstring | undefined
Source of the after layer (right, full frame). Defaults to beforeSrc.
beforeAlt
before-alt
string
''
Alt text for the before layer. Empty (the default) leaves it decorative; set it, with afterAlt, when the comparison itself is the content rather than an illustration beside prose.
beforeFilter
before-filter
stringstring | undefined
CSS filter applied to the before layer, e.g. grayscale(1) contrast(0.7).
beforeLabel
before-label
stringstring | undefined
Uppercase tag at the top left.
beforeSrc*
before-src
string
Source of the before layer (left).
height
height
number
240
Frame height in px.
ratio
ratio
number
0.5
Divider position, 0..1 of the width. Mutable; clamped to 0.04..0.96 so the handle stays on the frame, wherever the value came from. A press anywhere on the frame moves the divider there and starts a drag, as one range input over the picture would; the handle itself drags from where it is and is the keyboard slider.
Events
Event
Detail
React
Vue
Description
suiError
string
onSuiError
@sui-error
Fires when the before or the after picture fails to load, once per source; detail is the source. With either lost there is nothing to compare, so the frame shows the image glyph and a quiet line and drops its divider and labels. Does not bubble.
suiResize
number
onSuiResize
@sui-resize
Fires while the divider moves (every drag step and every key press); detail is the new ratio (0.04..0.96). The pair is sui-splitter's for the same ratio: a state report, not a field's value. Does not bubble.
suiResizeEnd
number
onSuiResizeEnd
@sui-resize-end
Fires when a move commits: on pointer release, or straight away on a key press. Detail is the ratio (0.04..0.96). Do the expensive work here. Does not bubble.
Methods
Method
Signature
Description
setFocus()
setFocus() => Promise<void>
Moves focus to the divider, the keyboard slider. A frame whose pictures failed has no divider and keeps focus where it is. The host's own focus() does the same.
Theming
Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.