Skip to content

Commit a61cc7a

Browse files
committed
feat: apply inert to outroing elements
that way they are invisible to assistive technology and can't be interacted with, which makes sense since the element is already "dead" and only transitioning out at this point closes #8445
1 parent a40af4d commit a61cc7a

File tree

4 files changed

+78
-2
lines changed

4 files changed

+78
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* **breaking** Error on falsy values instead of stores passed to `derived` ([#7947](https://github.com/sveltejs/svelte/pull/7947))
1717
* **breaking** Custom store implementers now need to pass an `update` function additionally to the `set` function ([#6750](https://github.com/sveltejs/svelte/pull/6750))
1818
* **breaking** Change order in which preprocessors are applied ([#8618](https://github.com/sveltejs/svelte/pull/8618))
19+
* **breaking** apply `inert` to outroing elements ([#8627](https://github.com/sveltejs/svelte/pull/8627))
1920
* Add a way to modify attributes for script/style preprocessors ([#8618](https://github.com/sveltejs/svelte/pull/8618))
2021
* Improve hydration speed by adding `data-svelte-h` attribute to detect unchanged HTML elements ([#7426](https://github.com/sveltejs/svelte/pull/7426))
2122
* Add `a11y no-noninteractive-element-interactions` rule ([#8391](https://github.com/sveltejs/svelte/pull/8391))

src/runtime/internal/transitions.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,15 @@ export function create_in_transition(node, fn, params) {
186186
* @returns {{ end(reset: any): void; }}
187187
*/
188188
export function create_out_transition(node, fn, params) {
189-
/**
190-
* @type {TransitionOptions} */
189+
/** @type {TransitionOptions} */
191190
const options = { direction: 'out' };
192191
let config = fn(node, params, options);
193192
let running = true;
194193
let animation_name;
195194
const group = outros;
196195
group.r += 1;
196+
/** @type {boolean} */
197+
let original_inert_value;
197198

198199
/**
199200
* @returns {void} */
@@ -205,10 +206,18 @@ export function create_out_transition(node, fn, params) {
205206
tick = noop,
206207
css
207208
} = config || null_transition;
209+
208210
if (css) animation_name = create_rule(node, 1, 0, duration, delay, easing, css);
211+
209212
const start_time = now() + delay;
210213
const end_time = start_time + duration;
211214
add_render_callback(() => dispatch(node, false, 'start'));
215+
216+
if ('inert' in node) {
217+
original_inert_value = /** @type {HTMLElement} */ (node).inert;
218+
node.inert = true;
219+
}
220+
212221
loop((now) => {
213222
if (running) {
214223
if (now >= end_time) {
@@ -229,6 +238,7 @@ export function create_out_transition(node, fn, params) {
229238
return running;
230239
});
231240
}
241+
232242
if (is_function(config)) {
233243
wait().then(() => {
234244
// @ts-ignore
@@ -238,8 +248,12 @@ export function create_out_transition(node, fn, params) {
238248
} else {
239249
go();
240250
}
251+
241252
return {
242253
end(reset) {
254+
if (reset && 'inert' in node) {
255+
node.inert = original_inert_value;
256+
}
243257
if (reset && config.tick) {
244258
config.tick(1, 0);
245259
}
@@ -274,6 +288,9 @@ export function create_bidirectional_transition(node, fn, params, intro) {
274288
let pending_program = null;
275289
let animation_name = null;
276290

291+
/** @type {boolean} */
292+
let original_inert_value;
293+
277294
/**
278295
* @returns {void} */
279296
function clear_animation() {
@@ -318,11 +335,25 @@ export function create_bidirectional_transition(node, fn, params, intro) {
318335
start: now() + delay,
319336
b
320337
};
338+
321339
if (!b) {
322340
// @ts-ignore todo: improve typings
323341
program.group = outros;
324342
outros.r += 1;
325343
}
344+
345+
if ('inert' in node) {
346+
if (b) {
347+
if (original_inert_value !== undefined) {
348+
// aborted/reversed outro — restore previous inert value
349+
node.inert = original_inert_value;
350+
}
351+
} else {
352+
original_inert_value = /** @type {HTMLElement} */ (node).inert;
353+
node.inert = true;
354+
}
355+
}
356+
326357
if (running_program || pending_program) {
327358
pending_program = program;
328359
} else {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export default {
2+
async test({ assert, component, target, raf }) {
3+
// jsdom doesn't set the inert attribute, and the transition checks if it exists, so set it manually to trigger the inert logic
4+
target.querySelector('button.a').inert = false;
5+
target.querySelector('button.b').inert = false;
6+
7+
// check and abort halfway through the outro transition
8+
component.visible = false;
9+
raf.tick(50);
10+
assert.strictEqual(target.querySelector('button.a').inert, true);
11+
assert.strictEqual(target.querySelector('button.b').inert, true);
12+
13+
component.visible = true;
14+
assert.strictEqual(target.querySelector('button.a').inert, false);
15+
assert.strictEqual(target.querySelector('button.b').inert, false);
16+
17+
// let it transition out completely and then back in
18+
component.visible = false;
19+
raf.tick(101);
20+
component.visible = true;
21+
raf.tick(50);
22+
assert.strictEqual(target.querySelector('button.a').inert, false);
23+
assert.strictEqual(target.querySelector('button.b').inert, false);
24+
raf.tick(51);
25+
assert.strictEqual(target.querySelector('button.a').inert, false);
26+
assert.strictEqual(target.querySelector('button.b').inert, false);
27+
}
28+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script>
2+
export let visible = true;
3+
4+
function slide(_, params) {
5+
return params;
6+
}
7+
</script>
8+
9+
{#if visible}
10+
<button class="a" transition:slide={{ duration: 100 }}>
11+
foo
12+
</button>
13+
<button class="b" out:slide={{ duration: 100 }}>
14+
bar
15+
</button>
16+
{/if}

0 commit comments

Comments
 (0)