Element-scoped view transition

요소 범위 뷰 전환

A transition can be scoped to one element while the rest of the page stays interactive.

···
html
<div class="v"><header>SCOPED TRANSITION <span>outside stays live</span></header><div class="stage scoped"><div class="scope" id="scope"><div class="tile" id="tile">A</div><div class="tile">B</div></div><div class="outside">LIVE<br><b id="pulse">0</b></div></div><div class="muted">transition boundary: card region</div></div>
css
.v{width:min(94vw,760px);height:min(88vh,320px);padding:clamp(9px,2.4vmin,18px);border:1px solid var(--line);border-radius:12px;background:var(--surface);font:500 clamp(12px,2.4vmin,16px)/1.3 var(--font-sans,system-ui,sans-serif);display:flex;flex-direction:column;gap:clamp(5px,1.4vmin,10px);overflow:hidden}.v header{display:flex;align-items:center;justify-content:space-between;gap:8px;color:var(--accent);font-weight:700}.v header span{color:var(--muted);font-weight:500}.v .stage{flex:1;min-height:0;position:relative}.v .muted{color:var(--muted)}.v .active{background:color-mix(in srgb,var(--accent) 18%,var(--surface));border-color:var(--accent)!important;color:var(--fg)}.v button{font:inherit;color:var(--fg);background:var(--bg);border:1px solid var(--line);border-radius:7px;padding:5px 8px;cursor:pointer}.scoped{display:flex;align-items:center;justify-content:center;gap:12px}.scope{width:60%;height:75%;border:2px dashed var(--accent);border-radius:9px;display:flex;align-items:center;justify-content:space-around;padding:8px}.tile{width:35%;height:55%;display:grid;place-items:center;border-radius:8px;background:var(--accent);color:var(--bg);font-weight:700;transition:transform .6s,background .6s}.scope.swap .tile:first-child{transform:translateX(125%);background:var(--accent-2)}.scope.swap .tile:last-child{transform:translateX(-125%)}.outside{padding:8px;border:1px solid var(--line);border-radius:8px;text-align:center;color:var(--muted)}.outside b{color:var(--accent)}
js
let swap=false,count=0;const scope=document.getElementById("scope");function tick(){swap=!swap;const update=()=>scope.classList.toggle("swap",swap);if(scope.startViewTransition)scope.startViewTransition(update);else update()}tick();setInterval(tick,1200);setInterval(()=>{document.getElementById("pulse").textContent=++count},450)

`Element.startViewTransition()` connects old and new states within a selected subtree. Unlike a document-wide transition, outside controls can remain interactive.

The demo swaps only the card region while a side counter keeps running. Because this is a newer browser feature, check support and fall back to ordinary DOM updates.

When to use

Use it for filtering or rearranging cards without blocking surrounding controls.

Open as page ↗