Titouan Mathis

CTO at Studio Meta and ikko

What's new in @studiometa/ui 1.10.0

06/08/2026 in #studiometa-ui #release

@studiometa/ui 1.10.0 is less about new components and more about how you load the library. The headline is autoloading: drop one <script type="module"> on a page and every component mounts itself from its data-component attribute, with no bundler and no manual registration. It ships a new @studiometa/ui/autoload entry powered by @studiometa/js-toolkit, adds a new @studiometa/ui-mapbox package for building Mapbox maps, introduces a Toaster notifications component, and modernises the build under the hood.

Table of content

Zero-build autoloading

The core of the release is the autoload runtime in @studiometa/js-toolkit: a small, generic runtime that scans the page for data-component tokens, imports each matching component on demand, and registers it. @studiometa/ui exposes it through a single @studiometa/ui/autoload side-effect entry — importing it is the whole contract; there is nothing to call.

Load it from an ESM CDN such as esm.sh, which serves the package as native ES modules and resolves its peer dependencies for you:

<script type="module">
  import 'https://esm.sh/@studiometa/ui@next/autoload';
</script>

<!-- Mounts on its own, no build step -->
<button data-component="Action" data-on:click="alert('Hello, no build step!')">Click me</button>

The exact same entry works when you bundle from npm: your bundler resolves it from node_modules and the behaviour is identical:

import '@studiometa/ui/autoload'; // @studiometa/ui components
import '@studiometa/ui-mapbox/autoload'; // @studiometa/ui-mapbox components

Import both entries together and they coalesce into a single loader over the composed set, so only one runtime ever scans the DOM.

Loading strategies

Each component carries a default strategy, overridable per element with data-load. A component loads eager (immediately), visible (near the viewport), idle (when the browser is idle), or on interaction (first hover, touch or focus):

<div data-component="ScrollAnimation" data-load="visible">…</div>

For above-the-fold components that must be ready right away, list them in a <meta> element and they load eagerly regardless of their default:

<meta name="js-toolkit:eager" content="Accordion, Action, Modal" />

See the Autoloading guide for the full picture: discovery, diagnostics and limitations.

Bring your own components

Because the autoloader is generic and works purely from a manifest, you can autoload your own js-toolkit components alongside the packaged ones. defineManifest describes a package: its name, a default loading strategy, and a modules record that maps each data-component token to a dynamic import. registerManifests registers one or more manifests with the shared runtime, and the last one wins on token collisions. Both come from @studiometa/js-toolkit:

import { registerManifests, defineManifest } from '@studiometa/js-toolkit';
import { manifest as uiManifest } from '@studiometa/ui/manifest';

const manifest = defineManifest({
  packageName: '@my/app',
  strategy: 'visible',
  modules: {
    MyComponent: () => import('./MyComponent.ts'),
  },
});

registerManifests(uiManifest, manifest);

Each entry points at a standard js-toolkit component, and the key you use in modules is the token the autoloader matches against data-component:

// MyComponent.ts
import { Base } from '@studiometa/js-toolkit';

export default class MyComponent extends Base {
  static config = {
    name: 'MyComponent',
  };
}

Writing the modules record by hand is fine for a few components. To register a whole folder at once, two adapters (fromMetaGlob for Vite, fromWebpackContext for webpack) turn a bundler glob into the same record:

const app = defineManifest({
  packageName: '@my/app',
  strategy: 'visible',
  modules: fromMetaGlob(import.meta.glob('./components/*/*.ts')),
});

With the glob adapters, the data-component token is derived from each file's name, so a MyComponent.ts mounts wherever data-component="MyComponent" appears, right next to the library's own components. The full workflow, including per-token overrides and constraints, is in the js-toolkit autoload API reference.

A new package for Mapbox

1.10.0 introduces @studiometa/ui-mapbox, a new package of js-toolkit components for building Mapbox maps: MapboxMap, markers, popups, clustering and a StoreLocator.

The mapbox-gl dependency is resolved lazily and not bundled by default. You provide it, which keeps you in control of its version and its Web Worker. In a no-build setup you point an import map at the source of your choice.

<script type="importmap">
  { "imports": { "mapbox-gl": "https://esm.sh/mapbox-gl@3" } }
</script>
<script type="module">
  import 'https://esm.sh/@studiometa/ui-mapbox@next/autoload';
</script>

In a bundled app, both mapbox-gl and @mapbox/mapbox-gl-geocoder are resolved from the installed NPM dependencies by default. You can also inject them through the provideMapboxGl / provideMapboxGeocoder helpers if you need more control.

New component: Toaster

Toaster is a headless notifications region. It is built on two permanent aria-live regions: a polite one for info and success, an assertive one for errors, so toasts are announced to screen readers without ever moving focus. Each toast is a Timer-based Toast with a pausable auto-dismiss countdown, and the stack animates through the viewTransition scheduler.

You provide the markup (one <template> the Toaster clones per notification) and trigger toasts declaratively from anywhere with Action:

<button
  type="button"
  data-component="Action"
  data-on:click="Toaster->target.show('Your changes have been saved.', { type: 'success' })">
  Save
</button>

Powered by @studiometa/js-toolkit 3.9.0

The autoloading described above is not a @studiometa/ui feature — it is a new framework-level capability in @studiometa/js-toolkit 3.9.0. Any js-toolkit application can autoload its own components the same way; @studiometa/ui 1.10.0 simply depends on it and ships the thin @studiometa/ui/autoload entry. The defineManifest / registerManifests helpers and the fromMetaGlob / fromWebpackContext adapters are exported from @studiometa/js-toolkit, and documented in its own autoloading guide and API reference.

The same release also gives js-toolkit per-symbol subpath imports: every export is now resolvable at its own extensionless subpath — @studiometa/js-toolkit/Base, @studiometa/js-toolkit/utils/damp, @studiometa/js-toolkit/registerManifests — each importable as a named or default export. Unbundled and CDN consumers can pull in just the one helper they need instead of the whole barrel.

Under the hood

We migrated every export * barrel re-export to explicit named export { … } matching the same change in @studiometa/js-toolkit 3.8.1. This helps improve static analysis of the packages and bundler performance when importing them.