BeforeAfter
componentTwo pictures one above the other, the first cut where a slider says.
Preview


Code
<twig:BeforeAfter label="Part of the first picture shown">
<twig:block name="before"><img src="/before.webp" alt="Before"></twig:block>
<twig:block name="after"><img src="/after.webp" alt="After"></twig:block>
</twig:BeforeAfter>


Code
<twig:BeforeAfter label="Part of the first picture shown">
<twig:block name="before"><img src="/before.webp" alt="Before"></twig:block>
<twig:block name="after"><img src="/after.webp" alt="After"></twig:block>
</twig:BeforeAfter>
Installation
php bin/console ux:install before-after --kit=github.com/parler-haut-interagir-librement/ux-kit
Props
| Prop | Type | Default | Description |
|---|---|---|---|
position |
int |
50 |
Where the cut starts, as a percentage. |
Accessibility
The slider is a native range: the arrows, Home and End are the browser’s, mirrored right to left. The position goes through a custom property set from the script, which a strict Content-Security-Policy allows. Without a script, the two pictures stand one under the other.
Files to copy
assets/controllers/before_after_controller.js
import { Controller } from '@hotwired/stimulus';
/*
* Moves the cut where the slider stands, through a custom property: nothing is written in the markup, which a strict
* Content-Security-Policy would refuse.
*/
export default class extends Controller {
static targets = ['range', 'before'];
connect() {
this.move();
}
move() {
this.element.style.setProperty('--phil-before-after-position', `${this.rangeTarget.value}%`);
}
}
templates/components/BeforeAfter.html.twig
{#-
# Two pictures one above the other, the first cut where a slider says. The slider is a native range: the arrows,
# Home and End are the browser's. Without a script, the two stand one under the other.
#}
{%- props
## string What the slider moves, read by screen readers.
label,
## int Where the cut starts, as a percentage.
position = 50
-%}
<div{{ attributes.defaults({class: 'isBeforeAfter', 'data-controller': 'before-after'}) }}>
<div class="isBeforeAfterAfter">
{##- What shows past the cut. -#}
{%- block after %}{% endblock -%}
</div>
<div class="isBeforeAfterBefore" data-before-after-target="before">
{##- What shows before the cut, cut by the slider. -#}
{%- block before %}{% endblock -%}
</div>
<input class="isBeforeAfterRange" type="range" min="0" max="100" step="1" value="{{ max(0, min(100, position)) }}" aria-label="{{ label }}" data-before-after-target="range" data-action="input->before-after#move">
</div>