@tooark/web-components
v1.2.2
Published
Tooark Web Components — Custom Elements (ark-*) (buttons, fields, dialogs, menus, calendar, key/value editor...) with Tailwind v4 and tokens
Readme
@tooark/web-components
The native Custom Elements (ark-*) of the Tooark design system, styled with Tailwind v4 on top of design tokens — accessibility, keyboard support and motion built in, one stylesheet, no framework required.
🌍 Languages:
English (this file) ·
Português
Contents
📖 Overview
The @tooark/web-components package provides:
- 41 elements: buttons and toggles, form fields (input, textarea, select, checkbox, radio, switch, file input, datepicker, key/value editor), overlays on the Popover API (dialog, drawer, menu, tooltip, command palette, toaster), layout (card, tabs, split pane, carousel), feedback (alert, badge, progress, spinner, skeleton, empty, status dot) and the calendar/clock/scheduler family;
- light DOM: components never move or wrap your children; the host is the control or container;
styles.cssis the only stylesheet you need: tokens, motion presets and component styles, all prefixed (ark:*,--ark-*), with no global reset;- themes by
color-scheme(theme="light|dark"per element), sizesxs…xl, intentsprimary…neutral,rounded; - events as
CustomEvents (change,ark-change,ark-select, …),testidforwarded asdata-testidon every internal part for E2E.
🔧 Installation
pnpm add @tooark/web-components # brings @tooark/core and @tooark/tokens as its own dependenciesThose dependencies are transitive: with pnpm (isolated node_modules) your code cannot import them. When it imports toast or announce from @tooark/core (as in the examples below), install the core too:
pnpm add @tooark/web-components @tooark/coreUsing React, Vue or Angular? Install @tooark/react, @tooark/vue or @tooark/angular instead: they depend on this package, add typed wrappers and re-export toast.
⚙️ Configuration
Import the stylesheet once and register the elements before using them:
import { registerTooarkComponents } from "@tooark/web-components";
import "@tooark/web-components/styles.css";
registerTooarkComponents(); // idempotentDeclare the page's color-scheme to pick the theme (light, dark or light dark to follow the system); set theme="light|dark" on an element to force one side, and lang="en|pt|es" (or lang="custom" with locale-json) on the elements that show text.
📦 Components
ark-alert— Alert/banner: the host is the box in the intent's soft color, your children are the message (free text or elements),slot="icon"left,slot="action"right,heading,dismissiblewith animated exit,liveregion (status/alert).ark-avatar— Avatar (role="img"named byname): initials fromname,srcimage that falls back to the initials on load error,size,shapecircle/square, customcolor.ark-badge— Short status/category label: intents,soft/solid/outline,xs–md,rounded, customcolorviacolor-mix. The host is the badge; icon and text stay as its children.ark-button— Intents, sizes, style variants (solid/outline/ghost),rounded(up tofull),loading/icon-only/full-widthstates,statusfeedback (success/error glyph + announcement), link mode (href).ark-calendar— Inline month grid (MUI DateCalendar-style): localized, WAI-ARIA keyboard navigation, motion, month/year views from the title and colored events (dots/count/list).ark-card— Card: the host is the box (surface,border,rounded) and a grid:heading(h2) orslot="header"withslot="actions"on the top row, unslotted children as the body,slot="footer"last with a divider;paddingnone–lg.ark-carousel— Native CSS scroll snap (touch/trackpad scroll natively, mouse drag emulated), autoplay, loop, dots and arrows. Slides stay as your direct children.ark-checkbox— Checkbox drawn by the component (role="checkbox"button + hidden native input for forms and<fieldset disabled>):checked,indeterminate,label/aria-label/free children as the label, sizes, intents. Emitschange.ark-clock— Time selection with scrollable digital columns (hours/minutes/seconds), 24h/12h, minute step, localized.ark-color-swatches— Color palette as aradiogroup: swatches fromcolors({ name, value }[], JSON attribute or JS property),value, arrows navigate,disabled,size. Emitschangewith the value.ark-command-item— Command palette item (the host is therole="option"): free children,slot="trailing"for a shortcut,value,group,label(filter text),disabled. Emitsark-select.ark-command-palette— Command palette on the Popover API: search field (anark-inputof its own),ark-command-itemchildren grouped and filtered (filter) or searched by the app (ark-query), arrows + Enter,hotkey(/,mod+k). Emitsark-select,ark-query,ark-open,ark-close.ark-copy-button— Copy button: extendsark-button(same variants, sizes,icon-only, forms, hooks); copiesvalueor theforelement, swaps the icon for a check and the text/titlefor "copied" forfeedback-ms, announces it. Emitsark-copy.ark-datepicker— Date/time picker composingark-input+ark-calendar+ark-clock:modedatetime (default)/date/time, inline orinputmode with field + popup, localized formatting, typed input parsing, forms.ark-dialog— Modal dialog on the Popover API (top layer,::backdropscrim, no portal): the host is the panel, your children are the body,slot="footer"is the footer; header fromlabel, focus trap, Esc/scrim,sm–xlorfull.ark-drawer— Drawer anchored to an edge:overlay(Popover API, scrim, focus trap, Esc) orinline(in the page flow, e.g. a bottom console);side,sizepreset or CSS length, header fromlabel,slot="footer", slide with thesheeteasing. Emitsark-open/ark-close.ark-empty— Empty state: dashed box with a dimmedslot="icon",heading(h3),descriptionand an optionalslot="action"button; children stay in place, ordered by CSS.ark-file-input— File field with theark-inputgrid (label, helper/error): hidden native<input type="file">for forms, drop zone withdragoverhighlight, keyboard-accessible choose button, list of selected names,accept/multiple. Emitschangewith the files and announces them.ark-input— Standardized text field: label, helper/error with aria, prefix/suffix viaslot, passwordreveal, native attributes passed through, sizes, intents,rounded.ark-kbd— Keyboard key: the host is the key (mono, border,surface-muted, bottom edge) around your text;size.ark-kv-editor— Key/value editor: rows{ id, key, value, enabled }(JS property) to enable, edit, delete and add, optionaltypes/secret/descriptioncolumns, bulk mode askey:valuelines or JSON. Composes other ark-* controls. Emitschange,ark-add,ark-delete.ark-mark— Scope mark: one of six shapes (circle,square,triangle,diamond,star,hexagon) in acolor, color and shape together so identity never relies on color alone;size,label.ark-menu— Dropdown/context menu on the Popover API (role="menu",popover="auto"): anchored to a trigger byfor,align/directionwith flip, keyboard,openAt(x, y); items stay as children. Emitsark-select.ark-menu-item— Menu item (the host is the item): free children,slot="trailing",disabled,intent,checked(checkbox item),divider,static(non-interactive content).ark-progress— Progress bar (role="progressbar"on the host):value/maxwith token-driven width transition,show-value,indeterminateloop exempt from reduced motion,label, sizes, intents.ark-radio— Radio drawn by the component (role="radio"button + hidden native input): groups bynamein the same form, one tab stop per group, arrows move and check,label/children as the label. Emitschangeon the one checked.ark-scheduler— Scheduler withweek/dayviews (time grid with overlap resolved into columns), plusmonthandagenda; colored, clickable events.ark-select— Native<select>styled likeark-input: label, helper/error with aria,placeholder, options from data (optionsJSON attribute or JS property,group→<optgroup>), sizes, intents,rounded.ark-shape-picker— Shape picker as aradiogroup: the sixark-markshapes drawn incolor,value, arrows navigate, localized shape names,disabled,size. Emitschangewith the shape.ark-skeleton— Loading placeholder: the host is the block (.ark-skeleton,aria-hidden), sized by your class/style;rowsrenders bars,animatedopts into the shimmer (a sweeping highlight),rounded.ark-spinner— Standalone loading indicator (role="status"): the button's spinner SVG on.ark-animate-spin(keeps spinning under reduced motion), screen-reader label bylangorlabel,size, optionalintent(inherits the text color otherwise).ark-split-pane— Resizable panels: your children are the panels, the handles are the component's own nodes at the end of the host;direction,sizes(percentages, rewritten on every change),data-min/data-maxper panel, keyboard and pointer-capture drag. Emitsark-resize.ark-status-dot— Status dot: the host is the circle in the intent color (defaultneutral);labelmakes it a namedrole="img", without it it is decorative;size. Static, never pulses.ark-switch— Accessible on/off switch (role="switch"): optional ON/OFF text and ✓/✕ icons, intents, form participation via hidden checkbox.ark-tab— Tab item (role="tab", the host is the control): free children,disabled,controls,closableanddirtyin the editor variant. Emitsark-close.ark-tabs— Tab strip (role="tablist"):underline/chips/editor, roving tabindex with arrows/Home/End,slot="actions"at the end,changewith the active value. Panels stay with the app.ark-textarea— Multi-line field with theark-inputgrid:rows,autosize(nativefield-sizing, JS fallback),monospace,resize, helper/error with aria, sizes, intents,rounded.ark-toaster— Sonner-style toasts: programmatic API, positions, rich colors, actions, animated enter/exit, localized close button.ark-toggle— Pressed-state button (aria-pressed), standalone (outline/tinted per intent) or as a group item.ark-toggle-group— Segmented control: exclusive (default) or multiple selection, syncedvalue, propagatessize/intent/theme/disabledto items.ark-tooltip— Tooltip on the Popover API: wraps your trigger without moving it, text viacontentor richslot="content",sidewith flip,delay, hover/focus/Esc,aria-describedbyon the trigger.
Full attribute reference, theming guide and E2E hooks: https://github.com/Tooark/web-components#readme · live examples with interaction tests: Storybook.
📝 Usage examples
A form with a confirmation dialog and a toast
<form id="profile">
<ark-input name="name" label="Name" placeholder="Your full name" required></ark-input>
<ark-select
name="role"
label="Role"
options='[{"value":"dev","label":"Developer"},{"value":"ops","label":"Operations"}]'
></ark-select>
<ark-datepicker input mode="date" lang="en" name="since"></ark-datepicker>
<ark-button type="submit" intent="primary">Save</ark-button>
</form>
<ark-dialog id="confirm" label="Publish changes?">
<p>Your profile will be visible to the whole team.</p>
<div slot="footer">
<ark-button variant="ghost" data-action="cancel">Cancel</ark-button>
<ark-button intent="primary" data-action="publish">Publish</ark-button>
</div>
</ark-dialog>
<ark-toaster position="bottom-right"></ark-toaster>Wiring it up
import { toast } from "@tooark/core";
const form = document.querySelector<HTMLFormElement>("#profile")!;
const dialog = document.querySelector("ark-dialog")!;
form.addEventListener("submit", (event) => {
event.preventDefault();
dialog.show(); // top layer, focus trapped, Esc and the scrim close it
});
dialog.addEventListener("click", (event) => {
const action = (event.target as HTMLElement).closest("[data-action]")?.getAttribute("data-action");
if (action === "publish") {
const data = Object.fromEntries(new FormData(form)); // { name, role, since }
toast.success("Profile published", { description: `Welcome, ${data.name}.` });
}
if (action) dialog.close();
});Data through JS properties and consolidated events
const editor = document.querySelector("ark-kv-editor")!;
editor.rows = [{ id: "1", key: "Accept", value: "application/json", enabled: true }];
editor.addEventListener("change", (event) => save((event as CustomEvent<{ rows: unknown[] }>).detail.rows));
const menu = document.querySelector("ark-menu")!; // for="trigger-id"
menu.addEventListener("ark-select", (event) => run((event as CustomEvent<{ value: string }>).detail.value));📋 Dependencies
Installed automatically unless marked as peer; peer dependencies are yours to install (the ranges are what the package declares).
| Package | Version | Description |
| ---------------------------------------------------------------- | ------- | ---------------------------------------------------------------- |
| @tooark/core | ^1.2.2 | Types, i18n, toast/announce services, motion and overlay helpers |
| @tooark/tokens | ^1.2.2 | Design tokens (colors, sizes, motion) and primitive types |
| tslib | ^2.8.1 | TypeScript runtime helpers |
🪪 Contributing
Contributions are welcome! Open issues and pull requests in the Tooark/web-components repository; CONTRIBUTING.md covers the workflow, the commit convention and the checklist. @tooark/web-components is released in lockstep with every other @tooark/* package.
📄 License
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
