@ai-matrx/tap-target
v0.2.13
Published
The AI Matrx tap-target button system: an invisible 44x44 touch ring over a 28x28 visible pill and a 14x14 glyph, glass/transparent/solid/group variants with correct ref forwarding for Radix asChild triggers, inline labels, link/label/button trigger resol
Maintainers
Readme
@ai-matrx/tap-target
The AI Matrx tap-target button system: an invisible 44×44 touch ring over a
28×28 visible pill and 14×14 glyph (32px target and 20px pill in the slim
group geometry), with press feedback, mobile tap hygiene (no 300ms delay, no iOS gray
flash), and correct ref forwarding for Radix asChild triggers.
- Primitives —
TapTargetButton(glass),TapTargetButtonTransparent,TapTargetButtonSolid,TapTargetButtonDestructive,TapTargetButtonForGroup+TapTargetButtonGroup, and theTapTargetLabeledcaption wrapper. - ~60 pre-composed buttons —
BugTapButton,PlusTapButton,TrashTapButton, … one import, one tag, zero configuration, all glyphs inlined. Opt-in via the./buttonssubpath. - Every button can be a button, label, or link (
as="label",href), carries automatic tooltip wiring fromariaLabel, and supports an inline caption (label) that widens the pill.
npm install @ai-matrx/tap-targetPeer: react >= 18. The canonical primitive, geometry and tooltip behavior
come from the regular @ai-matrx/design-system dependency.
Setup — two one-time steps
1. Import the stylesheet once at your app root. The CSS is part of the product — the 44×44 ring / pill geometry and press feedback live in it, and nothing renders correctly without it:
// app/layout.tsx (or your root entry)
import "@ai-matrx/tap-target/styles.css";That one line is enough: since 0.2.1 this sheet @imports
@ai-matrx/design-system/styles.css, which it REQUIRES — the loading button's
spinner wears design-system's matrx-spin, whose keyframe is defined there
(never animate-spin, a host utility this package cannot ship). If your app
already imports the design-system sheet, nothing is duplicated.
Tailwind users migrating from the in-repo Matrx copy can keep their existing
globals.css .matrx-tap-* block until the C9 swap removes it — the rules are
identical; just don't load both forever.
2. Mount a tooltip provider near the root (skip if your app already mounts
@radix-ui/react-tooltip's provider):
import { TooltipProvider } from "@ai-matrx/tap-target";
<TooltipProvider delayDuration={300}>{children}</TooltipProvider>Link component registration
href on any tap button renders a link. External hrefs (http(s):, mailto:,
tel:) always render <a target="_blank" rel="noopener noreferrer">. Internal
hrefs render through your router's link component — register it once at
startup:
import Link from "next/link";
import { setTapTargetLinkComponent } from "@ai-matrx/tap-target";
setTapTargetLinkComponent(Link); // e.g. in a client boot componentWithout a registration, internal hrefs fall back to a plain <a> (still a
working link — no prefetch, no client-side routing). A per-instance override
is also available: <TapTargetButton href="/tasks" linkComponent={Link} />.
Usage
import { TapTargetButton, TapTargetButtonGroup, TapTargetButtonForGroup } from "@ai-matrx/tap-target";
import { PlusTapButton, TrashTapButton } from "@ai-matrx/tap-target/buttons";
// Pre-composed (preferred): one tag, tooltip auto-derives from ariaLabel
<PlusTapButton onClick={add} ariaLabel="Add a task" />
// Variants: glass (default) | transparent | solid | group
<TrashTapButton variant="solid" bgColor="bg-destructive" iconColor="text-destructive-foreground" />
// Links
<PlusTapButton href="/tasks/new" ariaLabel="New task" />
// Inline caption (widens the pill, tooltip off — the label self-describes)
<PlusTapButton label="Add" />
// Grouped slim buttons in one shared glass shell
<TapTargetButtonGroup>
<TapTargetButtonForGroup ariaLabel="Undo" icon={<UndoIcon />} />
<TapTargetButtonForGroup ariaLabel="Redo" icon={<RedoIcon />} />
</TapTargetButtonGroup>
// Custom glyph via the primitive
<TapTargetButton ariaLabel="Custom" icon={<MyIcon className="h-4 w-4" />} />Refs forward to the underlying <button>, so every button works as a Radix
asChild trigger (DropdownMenu, Popover, Tooltip, …):
<DropdownMenuTrigger asChild>
<MoreHorizontalTapButton />
</DropdownMenuTrigger>Subpaths
| Subpath | What it is |
|---|---|
| . | Primitives, TapTargetLabeled, link registration, tooltip re-exports. |
| ./buttons | The ~60 pre-composed buttons (heavy — every glyph inlined; opt-in). |
| ./styles.css | The REQUIRED geometry/feedback stylesheet — import once at app root. |
| ./package.json | The manifest. |
Styling notes
- Geometry and press feedback come from
styles.css(.matrx-tap-*). To retune every tap button, that file is the single source of truth — never per-button size overrides. - Variant decoration uses Tailwind-style utility classes on the pill
(
bg-primary,hover:bg-muted,text-foreground, and the Matrxmatrx-glass-thin-border/matrx-glass-interactiveglass classes). In a Tailwind app these resolve against your theme tokens; make sure your Tailwind build scans this package (Tailwind v4:@source "../node_modules/@ai-matrx/tap-target";) and provide the twomatrx-glass-*classes (or accept an undecorated glass pill). - Never wrap a tap button in extra
p-*/m-*/gap-*— the invisible ring already reserves the spacing.
