npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@danxbot/ui

v3.4.3

Published

Danxbot — a domain-agnostic React design system with motion as a first-class primitive.

Readme

@danxbot/ui

A React design system with motion as a foundation, not a finish pass.

npm install @danxbot/ui
import { Button, Chat, ThemeMenu } from "@danxbot/ui";
/* your app's Tailwind entry — see Setup, all three lines are required */
@import "tailwindcss";
@import "@danxbot/ui/theme.css";
@import "@danxbot/ui/styles.css";

Requires React 19 and Tailwind CSS 4 in the consuming build — the package ships no compiled utilities, on purpose. MIT licensed.

What is in it

102 components across forms, overlays, structure, data, layout and chat.

Forms — Field, FieldSet, Input, Textarea, Checkbox, Switch, Radio, RadioCard, Select, Combobox, MultiCombobox, Slider, NumberInput, OTPInput, FileUpload, DatePicker, Toggle, ToggleGroup, Toolbar

Overlays — Dialog, AlertDialog, Popover, Tooltip, Toast, Menu, CommandPalette

Structure — Card, Tabs, Accordion, Breadcrumb, Pagination, AppShell, Separator, ScrollArea, Collapsible, PanelGroup

Display — Avatar, Progress, Meter, ProgressRing, Stat, Sparkline, Timeline, Tree, EmptyState, Badge, Icon, Spinner, Skeleton, LoadingOverlay

Data — DataTable

Chat — Chat, Message, MessageScroller, Composer, Markdown, CodeBlock, ToolCall, Attachment, ModelSelector, EffortControl, ContextMeter

The parts worth knowing about

Motion is a layer, not a decoration

Four spring curves are baked as CSS linear() easings. A spring curve encodes its damping ratio — its shape — and nothing else, so duration stays a free parameter and one curve is correct at any speed. There is no JavaScript animation runtime; the equivalent costs 35–40 KB to do what these do for free.

Reduced motion reduces. The usual animation-duration: 0.01ms !important sweep is wrong twice over: the spec asks for motion removed, reduced or replaced, and !important makes the decision unoverridable. Instead --motion-scale halves durations and --motion-travel zeroes distances, so components inherit the preference without knowing it exists.

Both themes come from one contract

Colour is a three-tier OKLCH system — primitives, semantic tokens, component tokens — and both themes are written against the same semantic names. Dark accents are hand-tuned at roughly 20% reduced chroma, because a large saturated fill on a dark surface reads as glare rather than emphasis.

Accessibility is a floor you can opt into

Contrast compliance is a switch (data-contrast="aa"), not a permanent state. Forcing AA everywhere flattens hierarchy: de-emphasised text stops being de-emphasised. The default is the palette as drawn; the AA overlay is one attribute away and honours prefers-contrast: more on first load.

Size is a multiplier, not a breakpoint

data-ui-scale sets a unitless multiplier over rem, which composes with the reader's own browser font size instead of overriding it. It moves type, spacing, control heights and icon sizes together, with hard floors so a tap target never drops below 24px.

Chat messages are typed parts

A message is a list of parts — text, code, reasoning, tool call, file, or a named application component — never a blob of markdown. An assistant turn routinely interleaves prose, a tool call and a confirmation button, and each is a different rendering problem. Applications register their own components by name, so a message can carry working UI:

<Chat
  messages={messages}
  components={{
    approval: (props, ctx) => (
      <ApprovalCard {...props} onApprove={ctx.app.approve} />
    ),
  }}
  appContext={{ approve }}
/>

Props are plain data and components are addressed by name, so a transcript stays serialisable — a component reference in the message would make it impossible to persist or replay.

Setup

Two stylesheets, and you want both. In your application's Tailwind entry:

@import "tailwindcss";
@import "@danxbot/ui/theme.css";   /* @source + the @theme bridge */
@import "@danxbot/ui/styles.css";  /* the token values, base layer and component CSS */

That is the whole contract. There is no layer-order statement to remember and no path to configure.

Your Tailwind build compiles this library's utilities, not ours. theme.css carries @source "./index.js", which points your compiler at the shipped bundle; the package itself ships zero generated utilities. That is deliberate and it is the fix for a real defect: a compiled stylesheet emits into @layer utilities, which is the same layer name your build uses, at equal specificity, imported last — so the library used to win every tie. Measured in a consuming app at 1440px, grid grid-cols-1 xl:grid-cols-[1.6fr_1fr] rendered one column and md:grid-cols-2 xl:grid-cols-3 rendered two. Nothing was misused; xl: is supposed to beat md: because Tailwind sorts breakpoints, and that guarantee only holds inside one compiler's output. So there is one compiler.

theme.css also carries the @theme bridge, extracted from source at build time, mapping every semantic token onto Tailwind's namespaces — without it your own bg-accent-subtle compiles to nothing, silently. Order matters: styles.css comes after, because it supplies the values the bridge points at.

Not using Tailwind 4? Then this package will not style anything: you get the tokens, the base layer and the hand-written component CSS, and no utilities at all. Components render structurally correct and visually unstyled — loudly, on the first screen, rather than as one breakpoint quietly misbehaving. Tailwind 4 in the consuming build is a requirement, not a recommendation.

Fonts are self-hosted woff2 subsets rather than CDN-loaded, because a blocked CDN renders every design in a system font with no error anywhere. They are pulled in by styles.css; @danxbot/ui/fonts.css exposes the @font-face rules on their own if you need them separately.

Preferences are read from <html> attributes so plain CSS and portalled content both see them:

import { useTheme, useUiScale, useContrast, useMotionPreference } from "@danxbot/ui";

ThemeMenu bundles all four into one popover.

Browser support

Modern evergreen browsers — Chrome, Safari, Firefox and modern mobile. That choice is what makes @property, @starting-style, container queries, field-sizing and OKLCH available without fallbacks.

Licence

MIT