
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
Making it easier to author CSS View Transitions
For the docs go here
A small JS library that implements common patterns on top of CSS view-transitions:
npm install velvette
import {Velvette, startViewTransition} from "velvette";
Or directly in the browser:
<script src="https://www.unpkg.com/velvette@0.1.6/dist/browser/velvette.js">
<script>
// You now have `Velvette` in your window object.
Velvette.startViewTransition(...)
const velvette = new Velvette(config);
</script>
CSS View Transitions, released in 2022, allow smooth transitions between different states of the same page, and soon they would allow smooth transitions between different documents of the same origin.
As it happens with web platform features, the patterns for using the feature emerged after its release. We've found that people who use CSS view-transitions often end up running into similar challenges and gotchas, having to write similar broilerplate code to overcome them.
Velvette is a library that allows you to specify in a declarative way how your transitions should behave, in isolation or as a response to a navigation,
and then apply the declaration to a particular ViewTransition, NavigateEvent, or
use it to handle cross-document ("MPA") navigations.
The Chrome team is definitely doing that! But implementing browser features takes time, and requires a consensus among many players. Implementing them now in JS allows authors to use them ergonomically today, and also gives us an experimentation ground to new ideas before they mature enough to go into the spec.
Velvette handles these features by attaching to the ViewTransition's promises, and changing the DOM in the following ways:
view-transition-name properties according to rules.(From simple to complex)
See #9424. Sometimes we want to style the transition based on "old" and "new" states.
Velvette does this automatically when a transition is extended, by setting
temporary classes vt-old and vt-new on the document element:
import {startViewTransition} from "velvette";
startViewTransition({update: updateTheDOMSomehow})
:root.vt-old #foo { view-transition-name: item; }
:root.vt-new #bar { view-transition-name: item; }
See isue #8960
When there are multiple transitions in the same page, it's hard to define what is captured, often leading to over-capturing unnecessary elements.
To specify a temporary class, extend a ViewTransition like so:
import {startViewTransition} from "velvette";
startViewTransition({update: updateTheDOMSomehow, classes: ["slide-main"]});
:root.vt-slide-main main {
view-transition-name: main;
}
See #8320.
Some view-transitions operate on many elements in a page, rather than
on a given set of elements. A common use-case for this is animated list-sorting.
Setting unique view-transition-name properties on all the participating elements
could become a tideous job.
Velvette implements this in the form of attribute substitution:
<main>
<div class="box" id="box1"><img src="..."></div>
<div class="box" id="box2"><img src="..."></div>
</main>
import {extend} from "velvette";
extend(viewTransition).capture(".box[:id] img", "$(id)");
This would generate the following temporary CSS (as inline styles) while capturing the transition:
.box#box1 img { view-transition-name: box1 }
.box#box2 img { view-transition-name: box2 }
When we capture multiple elements under different names, we might want to apply the same styles to their corresponding pseudo-elements.
For example, in the example above, we might want all the boxes to animate for a 1 second duration.
We do this by extending the view transition with a style that matches a capture, like so:
startViewTransition({
update,
captures: {".box[:id] img": "$(id).any-box"},
styles: {"::view-transition-group(.any-box)": {animationDuration: "1s"}}
})
This will generate styles for all the captured elements that fit the class, e.g.:
::view-transition-group(box1) { animation-duration: 1s }
::view-transition-group(box2) { animation-duration: 1s }
See issue #8685, issue #8925, issue #8683, and others.
A common use-case for CSS view-transitions is responding to a navigation, whether it's in the same document ("SPA") or across same-origin documents ("MPA").
To help with this, constucting a Velvette object with a certain configuration lets you
declare the rules to how different navigations should be handled.
A navigation consists of an old URL, a new URL, and a navigation type, which could be
"push", "replace", "reload", "traverse", "back", "forward", or "auto" ("auto" means everything except "reload").
To configure a Velvette object to handle navigations, we need to provide routes, rules, captures, and styles. For example:
new Velvette({
routes: {
"home": "/",
"about": "/about"
},
rules: [
{to: "home", type: "back", class: "slide-right"}
],
captures: {
"section#main": "main.slow"
},
styles: {
'::view-transition-group(".slow")': {animationDuration: "3s"}
}
});
When responding to a navigation, Velvette would find the last matching rule in the rules list,
and apply its class and parameters. If a matching rule is found, the view
transition would be invoked and the specified class, captures and styles would be activated,
exactly like calls to extend on a particular ViewTransition.
See issue #8209.
One thing that came up a lot from early adopters of CSS view-transitions is the difficulty to create
transitions between list & details pages, e.g. a playlist in https://example.com/playlist/ that
animates the song thumbnail to the hero in https://example.com/song/315 when selecting the
appropriate song in the playlist.
In Velvette, this is done in the navigation configuration, like so:
new Velvette({
routes: {
"playlist": "/playlist/",
"song": "/song/:song_id"
},
rules: [
// "with" would match both song<->playlist and playlist<->song
{with: ["song", "playlist"], class: "expand"}
],
captures: {
".vt-expand.vt-route-song img#song-artwork": "artwork",
".vt-expand.vt-route-playlist ul.playlist li#song-$(song_id) img.thumbnail": "artwork"
}
});
This example demonstrates several things that happen as a response to navigation:
vt-expand is applied for the entire duration of the transition.vt-route-song and vt-route-playlist are applied at the appropriate times only.$(song_id) string with the value of the song_id parameter
coming from either route (in this case, the song route).Once we have a configured Velvette object, we can apply it to navigations
in 3 different ways.
To potentially start a view transition for a same-document navigation, we simply call velvette.startNavigation, like so:
const velvette = new Velvette(config);
const transitionOrNull = velvette.startNavigation({
from: "https://example.com/old-url",
to: "https://example.com/new-url",
// "push" | "replace" | "traverse" | "reload"
navigationType,
// e.g. -1 is "back"
traverseDelta
}, async () => {
// update the DOM to the new state
});
This allows integrating Velvette with routers or other styles
of SPA authoring.
With the Navigation API, the information about old URL, new URL and navigation type
is already known to us, so Velvette provides a convenient way to use
CSS view-transitions together with it:
const velvette = new Velvette(config);
navigation.addEventListener("navigate", async event => {
if (shouldIntercept(event)) {
velvette.intercept(event, {
async handler() {
/* make actual changes based on the navigation */
}
});
}
});
Note: cross-document navigations are currently only available in Chrome canary with experimental web features flag enabled, and is missing a few key features.
Velvette already works with the current set of features, and aims to keep up with the changes until
cross-document view transitions are stable.
To apply a Velvette configuration for cross-document view transitions:
// This has to be called very early, before the first render opportunity.
// e.g. in a classic script in the <head>.
new Velvette(config).crossDocument();
FAQs
Make authoring CSS view-transitions easier
The npm package velvette receives a total of 14 weekly downloads. As such, velvette popularity was classified as not popular.
We found that velvette demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.