Needless UI
The Needlessly Engineered Styling Toolkit. An open-source UI component library for Angular, with React next. The name is a joke; the engineering isn't.
Everything is free, including what other libraries sell separately: a scheduler with resource timelines, repeating events and iCalendar files, and a data grid with grouping, tree data and Excel export. MIT, with no premium tier and no license key. Moving off a paid library? Read the guides for moving from FullCalendar and from AG Grid.
Early development (
0.x). APIs will change between minor versions until 1.0.
Why another component library
- No premium tier. Everything is MIT, including what other libraries often sell separately: the scheduler's resource timeline and recurring events, and the data grid's grouping, tree data and Excel export.
- Native elements first.
<button nuiButton>is a real<button>: native semantics, keyboard behavior and forms, with nothing wrapped around it. - One stylesheet for every framework. Components are styled by a framework-free CSS package. Angular and React bindings only set classes and
data-*attributes, so both frameworks look and behave the same. - Your CSS always wins. Everything ships inside
@layer nui.*, so plain CSS in your app overrides it without!importantor specificity battles. - Accessible by construction. Every color pair is checked against WCAG 2.2 AA when the palette is generated. Controls clear the 24px target minimum, and focus rings, forced colors and reduced motion are handled.
- Needlessly customizable. Springs, press effects, entrances, corner shapes, radius and density: one attribute for a whole subtree, or one input per component. The springs are real physics, solved at build time and shipped as CSS
linear()easings. - Standard design tokens. Tokens are W3C DTCG 2025.10 files, compiled to CSS custom properties with light and dark modes, including nested themes.
- Modern Angular. Signal inputs, zoneless, OnPush, SSR- and hydration-safe, with one entry point per component so apps only ship what they import.
Packages
| Package | What it is |
|---|---|
@needless-ui/tokens |
Design tokens in DTCG format, compiled to CSS custom properties |
@needless-ui/css |
Framework-free component styles in cascade layers; works in plain HTML |
@needless-ui/angular |
Angular 22 directives and components that apply those styles |
@needless-ui/react |
Planned |
Components
AI chat, Avatar, Breadcrumbs, Button, Calendar, Carousel, Color picker, Combobox, Command palette, Data grid, Date and time pickers, Dialog, Dropzone, Empty state, Input mask, Markdown, Menu, Number field, OTP input, Phone field, Popover and hovercard, Rating, Rich text editor, Scheduler and resource timeline, Select, Skeleton, Splitter, Toast and Tour. Each spec defines the API, keyboard behavior and accessibility, and every framework package implements it.
Quick start (Angular)
ng add @needless-ui/angular
That adds the package with Angular Aria and the CDK, and imports the styles at the top of your global stylesheet. By hand, it's:
pnpm add @needless-ui/angular @angular/aria @angular/cdk
/* src/styles.css */
@layer reset, nui, app; /* optional: keeps your resets from overriding components */
@import '@needless-ui/css';
With Tailwind CSS, components go after Tailwind's base styles and before its utilities: @layer theme, base, nui, components, utilities; (ng add writes that line when it finds Tailwind).
Use a component:
import { Component } from '@angular/core';
import { NuiButton } from '@needless-ui/angular/button';
@Component({
selector: 'app-root',
imports: [NuiButton],
template: `<button nuiButton variant="soft" tone="danger" (click)="remove()">Delete</button>`,
})
export class App {
remove() {}
}
Plain HTML
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@needless-ui/css/dist/needless-ui.min.css"
/>
<button class="nui-button" data-variant="outline" data-tone="neutral">
It works without a framework
</button>
Starter app
templates/room-booking is a working Angular app built on the scheduler and the data grid: rooms on a timeline, bookings grouped by room, and Excel and calendar exports. Its README deploys it to Vercel or opens it in StackBlitz in one click.
Customization
Any element can give everything inside it a personality, and components take the same values as inputs:
<body data-nui-motion="jelly" data-nui-press="squish" data-nui-corners="squircle">
<button nuiButton press="rubber" [spring]="{ stiffness: 900, damping: 12 }">Boing</button>
</body>
See the customization spec, or play with it at needlessui.com/guides/customization.
Theming
- Light and dark follow the operating system. Pin a theme on any element with
data-nui-theme="light"or"dark"; themes can nest. - Override a token anywhere, e.g.
:root { --nui-color-accent-solid: oklch(0.55 0.2 150); }. - Change the brand palette by editing the palette config in
packages/tokens/scripts/palette.tsand regenerating. Contrast is re-checked automatically.
Browser support
| Browser | From |
|---|---|
| Chrome and Edge, on computers and Android | 120 |
| Firefox, on computers and Android | 125 |
| Safari on Mac | 17 |
| Every browser on iPhone and iPad | iOS 17 |
| Samsung Internet | 25 |
Every change runs the component tests in Chromium, Firefox and WebKit, and every docs page is checked in each of them, on a computer and on a touch screen. Components work with touch and down to 320px wide. Older browsers aren't supported: without the Popover API, menus, selects and popovers don't open there. What sets each version, what newer browsers add, and how it's tested: the browser support guide and the spec.
Repository layout
packages/
tokens/ DTCG token sources, palette generator, token compiler
css/ component styles (one file per component) and the bundler
angular/ @needless-ui/angular, one secondary entry point per component
apps/
docs/ the documentation site, www.needlessui.com (30 languages)
specs/ framework-agnostic contract for each component
Development
Requires Node.js 22.22+ or 24.15+ and pnpm 12.
pnpm install
pnpm dev # docs site at http://localhost:4200
pnpm test # token, CSS and Angular unit tests
pnpm build # tokens → css → Angular package in dist/
pnpm build:docs # prerendered docs site in dist/docs/browser
pnpm check:browsers # every page in Chromium, Firefox and WebKit, desktop and touch
See CONTRIBUTING.md before opening a pull request.
