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

@siriwatknp/mui-cli

v0.3.0

Published

Agent-facing CLI for theming Material UI components — knows every themable seam and outcome model, emits correct styleOverrides fragments

Readme

@siriwatknp/mui-cli

Theme Material UI components without doc-searching. The mui CLI knows every themable seam (component × slot × variant × CSS property) and every outcome model (how a Button's height is actually built: line-height + padding lever + min-height floor + borders), so it emits the exact styleOverrides fragment that lands your target — including the coupled writes and floor adjustments that hand-written overrides silently miss.

Built for coding agents first: predictable commands, copy-paste ids, --json envelopes everywhere. Humans welcome.

Install

Install as a devDependency inside your MUI project (peers resolve from your project):

npm i -D @siriwatknp/mui-cli
npx mui --help

Requirements per feature:

| Feature | Needs | | --- | --- | | component, search, theme (solve + fragment), demos | Node ≥ 20 only | | --theme <file> (solve against YOUR theme) | @mui/material in your project; typescript v5/v6 for .ts theme files | | compose, --js | typescript v5/v6 (v7's native compiler drops the JS API these features use) | | --measure (render + verify) | vite, @vitejs/plugin-react, react, react-dom, @emotion/react, @emotion/styled, playwright-core + Google Chrome installed |

A missing package prints the exact install command — nothing fails with a stack trace.

Agent setup

npx mui install --skill   # writes .claude/skills/mui-cli/ (Claude Code)
npx mui doctor            # per-feature readiness with exact fixes

install --skill generates an agent skill from the installed CLI (version-stamped — regenerate after upgrading). doctor checks each feature (solve / --theme / compose / --measure) and prints the exact install command for anything missing.

The 30-second tour

# 1. What can I theme on a component?
mui component Switch

# 2. Make it match a design (multiple outcomes merge into ONE fragment)
mui theme Switch --props size=small width=36 height=20 padding=0

# 3. Verify by rendering (needs Chrome)
mui theme Switch --props size=small width=36 height=20 padding=0 --measure

# 4. Solve against YOUR theme, not vanilla defaults
mui theme Button height=36 --theme ./src/theme.ts

# 5. Grab a runnable docs demo, or compose several into one file
mui component Switch --list-demos
mui compose Switch:BasicSwitches Button:BasicButtons --theme ./src/theme.ts -o demos.tsx

Every command accepts --json for a typed { type, data } envelope.

Commands

component [Name] — discover

  • mui component — all components with their seam counts and available outcome nouns.
  • mui component Switch — the catalog for one component: outcomes first (each with a runnable command), then its composition tree (what it extends / is part of / where its content font comes from), then every seam grouped by slot. Hidden derived seams are collapsed (--full shows them).
  • Wrapper components work too: mui component TextField shows the parts to theme (OutlinedInput, InputLabel, …).

Outcome lines are honest: an outcome that can't work prints REFUSED — <reason> instead of failing later. A note like "content follows theme.typography.button — pass --theme so the solve reads yours" tells you when your typography matters.

theme <Component> [outcome=px ...] — resolve

The core verb. You state outcomes; the CLI solves them against measured component state and emits one correct fragment to spread into createTheme():

mui theme Button height=36                          # bare = default size, every variant
mui theme Button height=36 --props size=small       # narrow the variant
mui theme Tooltip height=28 paddingInline=10        # merged: ONE fragment, no conflicts
mui theme Tooltip --slot arrow size=12              # slot-addressed outcomes
mui theme Switch --props size=small touch=24        # a11y tap box, visual untouched

What makes the output trustworthy:

  • The math is printed. Every run shows the model (height = max(minHeight, lineHeight + 2·paddingBlock + borders)), the current state, and each edit with its reason.
  • Traps are handled. min-height floors are lowered only when they block (a padding-only edit that silently does nothing is the classic hand-written failure); asymmetric label reserves are preserved; borders join the math; coupled writes (label margins, connector offsets) ride along annotated.
  • Refusals are information. "content is 24px — taller than the 20px target" means the font is the blocker; shrinking it is its own decision, never a silent emission.
  • Input-family baseline reset. Every input-family height solve (OutlinedInput, FilledInput, Input, Autocomplete) also emits height: 'auto' on the InputBase input and lineHeight: theme.typography.body1.lineHeight on the InputBase root AND FormLabel root (label metrics match the input line), so field content follows your typography instead of MUI's frozen 1.4375em line. The solve accounts for it (content = the body1 line box), and unasked sizes shift by exactly the line-box delta (vanilla: +1px).

Raw seam edits — the full flow

When no outcome covers what you need, edit a seam directly. The id is never guessed — it comes from the catalog:

mui component Accordion
#   Accordion · expanded margin
#     id: MuiAccordion|root|base|&.Mui-expanded|margin     ← copy this

mui theme Accordion --set 'MuiAccordion|root|base|&.Mui-expanded|margin=0px'

--set values are verbatim CSS, applied after outcomes (adjustment wins). Hidden seams refuse with the driver id to set instead.

--theme <file> — solve against your theme

mui theme Button height=36 --theme ./src/theme.ts

Instant (no browser): the file is imported in-process, resolved with createTheme, and the solve reads your values — typography-driven content sizes, overridden paddings/floors/borders, defaultProps, even function styleOverrides (executed with a synthesized ownerState). Rules:

  • Inline JSON works for quick probes — --theme '{"typography":{"body1":{"fontSize":14}}}' (strict JSON; file paths for anything real).
  • Default-export either theme options or a createTheme(...) result — both are detected and handled.
  • .ts / .tsx files are transpiled in-process. A file with no imports (a plain options object) works from anywhere; a file that imports (e.g. it exports createTheme(...)) resolves those imports by walking up from its own directory — so it must sit somewhere a node_modules with @mui/material is reachable, like any real project file.
  • Anything statically unknowable (lineHeight: 'normal', opaque runtime values) is flagged in the rationale with "verify with --measure" — never silently guessed.

--measure — prove it

mui theme Button height=36 --theme ./src/theme.ts --measure

Renders baseline + fragment in headless Chrome (under your theme when --theme is given) and reports measured after applying: 36px ✓ per variant. This is the ground truth; exit code is non-zero on a miss.

--compare — see it

mui theme Button height=36 --theme ./new-theme.ts --compare            # before = MUI baseline
mui theme Button height=36 --theme ./new-theme.ts --compare ./old.ts   # before = old theme

One PNG, two panels: before (baseline or the given theme/inline JSON) and after (your theme + the solved fragment), red height rulers per variant, captions with the measured px (before — 56px / after — 36px ✓). Implies --measure — the verdict still prints and still gates the exit code. Output defaults to mui-compare-<Component>.png (--shot <path> overrides).

Docs demos — --list-demos, --demo, compose

Real runnable usage, synced from the Material UI docs (380 demos across 31 pages):

mui component Button --list-demos             # DEMO / SECTION / DESCRIPTION table
mui component Switch --demo ControlledSwitches        # prints the .tsx source
mui component Switch --demo ControlledSwitches --js   # types stripped, JSX kept
mui component Switch --demo ControlledSwitches --copy # → system clipboard instead

Demo names are the DEMO column verbatim (case-sensitive PascalCase); a miss prints the valid candidates. --copy writes the system clipboard (pbcopy on macOS, clip on Windows, wl-copy/xclip on Linux) and prints a one-line summary instead of the source.

compose merges several demos into ONE runnable file — imports deduped, name collisions auto-suffixed (label → label2, usages rewritten safely via the TypeScript AST), demo default-exports renamed and stacked:

mui compose Switch:BasicSwitches Checkbox:Checkboxes Tabs:BasicTabs \
  --theme ./src/theme.ts -o composed-demos.tsx
  • --theme wraps everything in <ThemeProvider> — createTheme(options) for an options file, the theme as-is for a createTheme(...) export; imported relative to -o.
  • A needs note (needs: @mui/icons-material/...) prints ONLY when the composition imports packages beyond react + @mui/material — no note means the file runs on @mui/material alone. Install the listed packages where the file will run; compose reports, it does not install.
  • Data files ride along. Demos that import docs data (./top100Films) pull those files in automatically: with -o they are written next to the output (emitted: top100Films.ts (data file of ComboBox)), including transitive imports (server.ts → movies.ts); --js transpiles them too. Without -o, a data file needed: note points at -o or --json (whose data.assets carries the sources). unresolved: ./x means the file was never captured at sync time — the output will not run as-is.
  • Rename notes (renamed: label → label2 …) print for every collision fix. With -o/--copy all notes go to stdout after the summary; when printing the source to stdout, notes go to stderr so pipes stay clean.
  • --js and --copy work here too.

MUI X demos — one resolver, three ways in

The same demo corpus for the four X products (1,168 demos across 158 features). X docs are organized by feature, not component, and X has no themable seams — so mui component <X> shows the product's feature map, and demos live one level down via mui demos.

mui component DataGrid                     # feature map (FEATURE / PLAN / DEMOS) — X has no seams
mui component DataGrid --list-demos        # ALL of the product's demos (grouped by FEATURE)
mui demos data-grid filtering              # one feature's demos (DEMO / PLAN / SECTION)
mui demos data-grid filtering QuickFilteringGrid --js   # demo name = trailing positional
mui demos tree-view rich-tree-view/items   # nested features address with a slash
  • Any export name is an entry point — DataGrid, DataGridPro, DataGridPremium, BarChart, DatePicker, RichTreeView… all resolve to their product, matching the package you import.
  • A PLAN column (community / pro / premium) is read from each demo's import package — a feature spanning tiers lists exactly the ones present (community,pro). Display-only: nothing is gated; the demo's own import line is the source of truth.
  • compose takes X picks as product/feature:Demo: mui compose data-grid/filtering:QuickFilteringGrid,ServerFilterGrid -o Grid.tsx. Imports dedupe, the needs: note lists the X packages, and data files emit next to -o — identical mechanics to core demos.
  • Licensing: MUI X is open-core. Community demos are MIT; Pro/Premium demos are example code for commercial packages and require a commercial MUI X license to run. This CLI ships the example source only — the PLAN column tells you which tier a demo needs.

Aliases & the demos shortcut

Every entry point runs through one resolver, so a token can be a canonical export, a friendly alias, or an X product:

mui tag                 # alias → `mui component Chip`
mui input               # alias → TextField   (also: icon→SvgIcon, dropdown→Select)
mui demos Button        # shortcut → `mui component Button --list-demos`
mui data-grid           # bare product → the DataGrid feature map

mui <alias> is shorthand for mui component <alias>. Unrecognized tokens fall through to "unknown command", so typos never silently resolve.

search <query> — find seams across components

mui search "button padding"

Reading the output

A fragment always prints ready to paste:

// Spread into your theme: createTheme({ ...,
components: {
  MuiButton: { styleOverrides: { root: { variants: [ … ] } } },
},
// })

Values are raw CSS. Rows the solver derived (identity fills, coupled writes) are marked derived in --json and yield to your explicit asks when invocations merge.

Versioning honesty

The bundled component-state data is measured against @mui/material 9.2.0 (the component/theme output states this). Solves without --theme reflect 9.x vanilla defaults; pass --theme (and --measure for ground truth) to solve against your project's reality.

License

MIT. The bundled docs-demo corpus (data/demos/) is derived from the Material UI documentation (MIT © Call-Em-All and MUI contributors). Not an official MUI product.