Skip to main content
All writing

Measuring style guide adoption

A proposed approach to measuring Rudiment UI adoption through custom-element tags, token references, and a read-only repository scan.

RUDI CHECK · REPOSITORY SCAN <rudi-button> <rudi-dialog> --rudi-color-accent OUTPUT Baseline report

What this covers.

  • A proposed scanner for component and token references.
  • What source-level counts can tell you, and where they need review.
  • A report schema and a staged approach to collecting a baseline.

A component library can be well documented and barely used. Measuring adoption starts with finding where its components and tokens appear in the products it serves.

This is a proposed specification for a read-only Rudiment UI scanner. The rudi check commands and reports below describe the intended interface; they are examples for a tool to be built and validated.

Why measure by namespace

Import-based measurement has to account for aliases, wrappers, and re-exports. A tag-based approach offers another useful signal: references to a library’s custom-element namespace in source files.

For Rudiment UI, <rudi-button> is a recognizable usage-site reference across template languages. A scanner can count that tag without first resolving which imported Button a file uses.

  • Identity is stable at the usage site. A scanner matches the tag name without tracing imports, resolving barrels, or guessing about wrappers.
  • Source and runtime answer different questions. Source references show where teams integrate the library. Runtime sampling shows what rendered in the states you visited. Keep those counts separate: one source reference may render many times or never render in a sampled session.
  • Other custom elements are review candidates. Separate rudi-* tags from other custom-element references. The latter may be product-specific elements, third-party dependencies, or duplicated patterns. Review them before calling them recreations.
  • Token references provide a second signal. Count var(--rudi-*) references and collect literal color values for review. A literal value may be an intentional exception; its presence alone does not establish token drift.
  • The namespace works with zero tooling. GitHub code search for rudi- across the organization gives you a rough adoption census before you build anything. The CLI below makes that structured, repeatable, and trackable.
  • Test each supported syntax. A shared namespace gives the scanner a common target across frameworks. Each parser still needs fixtures for the template languages and component wrappers used by consuming teams.

Static scanning can miss dynamically assembled tags and usage hidden behind wrappers. Document these limits in the report. Runtime sampling can supplement the scan, but its coverage depends on the pages and states visited.

The rudi check CLI

The proposed rudi check command would run at a repository root, parse supported source files, count namespace references, and emit a JSON report with review signals.

What it scans

SourceWhat it extracts
.html, .astro, .vue, .svelte, .jsx, .tsx, .js, .tsHyphenated element tags, split into rudi-* and foreign; bare interactive HTML elements (button, dialog, input, select, details); attributes passed per rudi-* element
Tagged template literals (Lit html, css)Same tag and attribute extraction inside the literal
.css, and <style> blocksvar(--rudi-*) references; non-token color values (hex, rgb(), hsl(), oklch()); --rudi-* overrides
package.json and lockfileDeclared and resolved versions of @rudi/* packages

Counting rule: count source-level references, not rendered instances. A rudi-button inside a shared header counts once, no matter how many pages render it. State this rule in every report so the numbers aren’t misread.

Output schema

An illustrative report, using example repository names, versions, and counts:

json snippet json
{
  "schemaVersion": 1,
  "generatedAt": "2026-07-21T06:00:00Z",
  "repo": "acme/checkout",
  "commit": "9f2c1ab",
  "scanner": { "name": "@rudi/check", "version": "0.1.0" },

  "versions": {
    "declared": { "@rudi/core": "^2.3.0" },
    "resolved": { "@rudi/core": "2.3.1" }
  },

  "elements": {
    "rudi-button": {
      "count": 42,
      "files": 17,
      "attributes": { "variant": 40, "disabled": 12, "class": 31 }
    },
    "rudi-dialog": { "count": 6, "files": 4, "attributes": { "open": 6 } }
  },

  "tokens": {
    "references": { "--rudi-color-surface": 12, "--rudi-space-3": 44 },
    "overrides": { "--rudi-color-accent": 2 }
  },

  "foreign": {
    "customElements": { "acme-card": 9, "acme-toggle": 3 },
    "bareInteractive": { "button": 4, "dialog": 1 },
    "hardcodedColors": { "count": 23, "files": 9 }
  },

  "coverage": {
    "elementCoverage": 0.87,
    "tokenCoverage": 0.79
  }
}

Field notes:

  • schemaVersion lets you evolve the format without breaking the dashboard. Bump it on any breaking change.
  • elements[*].attributes is the web components equivalent of prop tracking: frequent class or style usage can prompt a review of defaults. Confirm the reason with consumers before changing an API or removing an apparently unused attribute.
  • foreign.customElements lists non-library references for review. Names let a team investigate whether acme-toggle fills a legitimate product need or duplicates an existing pattern.
  • elementCoverage = rudi element references ÷ (rudi + foreign custom elements + bare interactive elements). tokenCoverage = token references ÷ (token references + hardcoded color values). These are source-reference ratios, not measures of visual quality or the percentage of a product using the system. Some non-library references are appropriate.
  • Version data rides along in every report, so version-lag tracking needs no separate pipeline.

Commands

Proposed command interface:

Code
rudi check                  # human-readable summary to stdout
rudi check --report out.json  # machine-readable report
rudi check --ignore "**/legacy/**"

Ship it as a report-only tool first. Don’t fail builds on adoption thresholds. Measurement tooling that blocks merges gets uninstalled; enforcement, if you want it, belongs in a later phase after teams trust the numbers.

GitHub Actions rollout

Start with a few repositories whose maintainers can check the results. Once the parsers and counting rules are reliable, a central scan could collect reports without requiring every team to install a workflow. The following is a rollout sketch; the scanner package and organization-scan script would need to be implemented first.

  1. Publish @rudi/check to your registry.
  2. Create a rudiment-metrics repository to hold reports and the dashboard.
  3. Add a scheduled workflow (weekly is enough) that lists organization repositories through the GitHub API, shallow-clones each, runs rudi check --report, and commits the output to data/<repo>/<date>.json.
  4. Build the dashboard as a static page that reads the JSON history. Astro fits, and it can live in the Field Guide, next to the docs that improve it.
  5. Later, offer an opt-in reusable workflow so teams can surface their own report as a PR comment.

Minimal workflow sketch:

yaml snippet yaml
name: rudiment-adoption-scan
on:
  schedule:
    - cron: '0 6 * * 1'
  workflow_dispatch:
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install -g @rudi/check
      - run: node scripts/scan-org.js # clones repos, runs rudi check, writes data/
        env:
          GH_TOKEN: ${{ secrets.ORG_READ_TOKEN }}
      - run: |
          git config user.name "rudi-bot"
          git config user.email "rudi-bot@users.noreply.github.com"
          git add data && git commit -m "chore: weekly adoption scan" && git push

Questions the data answers

  • Version lag: resolved @rudi/core versions across repositories, and how long each lags behind.
  • Component health: usage per component, attribute histograms, and override rates, ranked for improve-or-deprecate calls.
  • Non-library references: other custom elements per repository, with team review to identify genuine gaps or duplication.
  • Potential token drift: literal color values to review alongside intentional exceptions.
  • Coverage trend: element and token coverage per repository, week over week.

Scaling the approach

Begin with a small baseline and manually inspect a sample of matches and misses. Record the scanner version and counting rules so later reports remain interpretable. Expand to scheduled scans and dashboards when the numbers answer questions teams can act on.

Useful to your team?

Share on LinkedIn