Every component has a personality you can change: the spring it moves with, what a button does under your finger, how dialogs and menus arrive, the shape and size of their corners, and how much room they take. Each is one attribute for everything inside an element, or one input for a single component.

One attribute, a whole subtree

Put the data-nui-* attributes on <body> for the whole app, or on any element for one part of it. The nearest one wins, so they nest. They only set CSS custom properties, so they work the same with any framework, or none.

customize.html
<body data-nui-motion="bouncy" data-nui-corners="squircle">
<!-- Everything here bounces and has squircle corners… -->
<main data-nui-press="squish" data-nui-density="compact">
<!-- …buttons in here squish, and controls are compact… -->
</main>
<aside data-nui-motion="none" data-nui-radius="none">
<!-- …and nothing in here moves or has rounded corners. -->
</aside>
</body>

One component

In Angular, nuiButton, nuiDialog and nuiMenu take the same values as inputs. The inputs you leave unset follow the attributes around them.

customize-inputs.html
<button nuiButton press="rubber" motion="elastic">Boing</button>

<dialog nuiDialog [(open)]="editing" enter="flip" corners="squircle">…</dialog>

<button nuiButton [nuiMenuTrigger]="actions">Actions</button>
<div nuiMenu #actions="ngMenu" enter="unfold" motion="mechanical">…</div>

Springs, compiled to CSS

Motion is spring physics: stiffness, damping and mass instead of a duration and a curve. The token compiler solves each spring and writes it into CSS as the time it takes to settle and a linear() easing, so it runs on the compositor without JavaScript. Six springs ship as tokens, from --nui-spring-snappy to --nui-spring-mechanical, and --nui-motion holds the one in use.

Any other spring is one input away. Angular compiles it at runtime with the same solver, and springTransition() gives you the CSS for your own elements.

customize-spring.ts
import { springTransition } from '@needless-ui/angular';

// In a template, any spring is an input:
// <button nuiButton [spring]="{ stiffness: 900, damping: 12 }">Save</button>

// Anywhere else, compile it yourself:
const wobbly = springTransition({ stiffness: 120, damping: 4, mass: 1.2 });
// '4152ms linear(0, 0.014 0.41%, …, 1)'

const card = document.querySelector<HTMLElement>('.card')!;
card.style.transition = `transform ${wobbly}`;

Anything in between

The presets are shortcuts. Set the custom properties yourself for anything else: any transform for --nui-press and --nui-enter, any number for --nui-radius-scale and --nui-density.

customize.css
.checkout {
--nui-motion: var(--nui-spring-jelly);
--nui-press: scale(0.92) rotate(-2deg);
--nui-enter: translateY(100%);
--nui-radius-scale: 1.5;
--nui-density: 1.1;
}

Accessibility

When the system asks for reduced motion, springs collapse to an instant, and presses and entrances stop moving. Density never takes a control below the 24px target size of WCAG 2.2, and no preset touches colors, so every contrast check still holds. Browsers without corner-shape draw every corner round.