PettyUI
51 headless Web Components. Zero dependencies. ~5KB gzipped.
Built on browser-native APIs — Popover, <dialog>, Navigation API, View Transitions. No framework required. Works everywhere.
Install
npm install pettyui
Usage
Import what you need. Each component registers itself as a Custom Element.
<script type="module">
import "pettyui/dialog";
import "pettyui/select";
import "pettyui/tabs";
</script>
<petty-dialog>
<button commandfor="my-dlg" command="show-modal" type="button">Open</button>
<dialog id="my-dlg">
<h2>Hello</h2>
<p>This is a native dialog with ARIA linking, focus trap, and Escape — all from the browser.</p>
<button commandfor="my-dlg" command="close" type="button">Close</button>
</dialog>
</petty-dialog>
Components
Inputs — Button, TextField, NumberField, Checkbox, Switch, RadioGroup, Slider, Toggle, ToggleGroup, Select, Combobox, Listbox, TagsInput, Form, DatePicker
Navigation — Link, Breadcrumbs, Tabs, Accordion, Collapsible, Pagination, NavigationMenu, Wizard
Overlays — Dialog, AlertDialog, Drawer, Popover, Tooltip, HoverCard, DropdownMenu, ContextMenu, CommandPalette
Feedback — Alert, Toast, Progress, Meter, LoadingIndicator
Layout — Avatar, Badge, Card, Image, Separator, Skeleton
Data — Calendar, DataTable, VirtualList
Animation — Typewriter, Counter, Stagger, Reveal, Parallax
Why
- Zero runtime — 500-byte signals core. No virtual DOM, no framework overhead.
- Browser-native — Popover API for overlays,
<dialog>for modals, Navigation API for routing. No polyfills. - No Shadow DOM — Style with plain CSS, Tailwind, or anything. No
::part()needed. - AI-native — Zod schemas for every component. MCP tools for agent integration.
- Works everywhere — React, Vue, Svelte, Astro, plain HTML. It's just Custom Elements.
Styling
PettyUI is headless. Components use data-state and data-part attributes for styling hooks.
petty-tab[data-state="active"] {
border-bottom: 2px solid blue;
}
petty-switch[data-state="on"] [data-part="thumb"] {
transform: translateX(18px);
}
Optional default theme and animations:
import "pettyui/theme";
import "pettyui/animations";
Signals
Built-in reactivity in ~30 lines (~500 bytes):
import { signal, effect } from "pettyui/signals";
const count = signal(0);
effect(() => console.log(count.get()));
count.set(1); // logs 1
Router
SPA routing with the Navigation API (~15 lines):
import { initRouter } from "pettyui/router";
initRouter();
<a href="/about">About</a>
<main data-petty-outlet><!-- content swaps here --></main>
License
MIT