From kiva-design-system
Pre-emptive audit and cleanup of <h1>-<h6> elements and tw-text-h1-h6 utility classes in repos that consume @kiva/kv-tokens, ahead of the semantic typography remap. Produces an audit inventory and applies per-usage fixes one heading level at a time.
How this skill is triggered — by the user, by Claude, or both
Slash command
/kiva-design-system:kiva-header-element-auditWhen to use
When a Kiva repo (kv-ui-elements or any consumer) needs to be prepared for the upcoming kv-tokens semantic typography mapping and you want to minimize visual churn. Trigger phrases - "header audit", "header cleanup", "typography header migration", "pre-empt the type style update".
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
`@kiva/kv-tokens` is moving toward a new semantic typography system. The `<h1>`–`<h6>` element defaults and `tw-text-h1`–`tw-text-h6` utility classes will eventually be remapped onto the new semantic styles. The classes and elements stay in use; their visual output shifts.
@kiva/kv-tokens is moving toward a new semantic typography system. The <h1>–<h6> element defaults and tw-text-h1–tw-text-h6 utility classes will eventually be remapped onto the new semantic styles. The classes and elements stay in use; their visual output shifts.
This skill audits every header usage in the target repo and applies pre-emptive per-usage fixes (element swap, class swap, both, or no-op) so the remap produces minimal visible churn.
@kiva/kv-tokens and the tw- prefix.typography.md skill in kv-tokens (@kiva/kv-skills/design-system/skills/kiva-design-system/typography.md) — it's the source of truth for the new mapping..vue (or .tsx/.jsx if extended later) component files in scope.keep — accept the new mapped style, no changeswap-class — replace the tw-text-hN class with another typography utilityswap-element — change the HTML element onlyswap-both — both element and class changedefer — flag for design-team review; not fixed in this passRun a single ripgrep pass across all in-scope packages. Match four surfaces (the fourth was added during real use):
<h[1-6]\b in <template>tw-text-h[1-6]@apply tw-text-h[1-6] declarations inside <style> / <style scoped> blocks<style> blocks (e.g. .tw-text-h1 u { ... }) — flag as source: style-selector--glob '**/*.vue'
--glob '!**/stories/**'
--glob '!**/.storybook/**'
--glob '!**/*.stories.*'
--glob '!**/tests/**'
--glob '!**/*.spec.*'
--glob '!**/dist/**'
--glob '!**/build/**'
--glob '!**/node_modules/**'
<h[1-6]\b|tw-text-h[1-6]|@apply\s+tw-text-h[1-6]
The element scan and class scan are usually best as separate rg runs to keep output legible:
# Element matches
rg -n --no-heading <globs> '<h[1-6]\b' <source-roots>
# Class matches (template + style-apply + style-selector all caught)
rg -n --no-heading <globs> 'tw-text-h[1-6]' <source-roots>
Then disambiguate template vs style-apply vs style-selector by inspecting whether the match line is inside <template>, contains @apply, or appears as a CSS selector inside <style>.
Write a Markdown working doc (default docs/header-cleanup-audit.md) with a Summary table and one section per heading level. Row columns:
| Column | Description |
|---|---|
package | Package name |
file | Path relative to repo root |
line | Line number |
level | 1–6 |
element | <hN> if present, else blank |
class | tw-text-hN if present, else blank |
source | template, style-apply, style-selector, or template+style-apply |
mismatch? | yes if element# ≠ class# on the same opening tag |
context | Trimmed match line (peek next line if opening tag has no inner text) |
decision | Filled in Phase 2 |
replacement | Filled in Phase 2 |
verified? | Filled in Phase 2 |
When an opening tag has both <hN> and tw-text-hM, emit one row at level = M (the class number). The element column shows the actual element; the mismatch flag is set when M ≠ N.
After populating, spot-check 3 random rows against the source files before continuing.
Run this six-step loop once per level, in order H4 → H1 → H2 → H3 → H5 → H6. H4 first because its rule is known (default class swap to tw-text-upper), which proves the loop and surfaces toolchain/test issues early.
decision and replacement for every row.verified?.decision, replacement (where applicable), and verified?.These are starting points. Refine against actual audit data per level.
| Level | Today | New mapped style | Likely visual delta | Starting hypothesis |
|---|---|---|---|---|
| H1 | Serif Medium, h1 scale, letter-spacing −0.5 | textHeadline — Serif Medium, semantic h1 scale, letter-spacing −200/−300 | Minor | Default keep. Inspect tight compositions for unwanted spacing shifts. |
| H2 | Serif Medium, h2 scale, letter-spacing normal→−0.3 | textHeadlineTwo — Serif Medium, semantic h2 scale, letter-spacing −200/−300 | Minor | Default keep. Watch for H2s used as eyebrows / small labels. |
| H3 | Sans Normal, letter-spacing −1, tight | textSubheadline — Sans Light, letter-spacing 0 | Notable: weight Normal → Light; tightening lost | Per-usage. Section sub-heading → likely keep; card/module title → likely swap-class to tw-text-title. |
| H4 | Sans Normal, uppercase, h4 scale | textTitle — Sans Normal, not uppercase, h3 scale | Major: loses uppercase, size grows | Default swap-class to tw-text-upper. Element case-by-case. |
| H5 | Sans Normal, h4.sm size | None (deprecated) | Unknown — depends on base CSS pruning | Default swap-element → <p> + tw-text-title / tw-text-label / tw-text-upper. |
| H6 | Not defined in kv-tokens | None (deprecated) | Already off-system | Default swap-element → <p> + a utility class chosen per usage. Treat as latent bug. |
These showed up as repeating shapes during the proving run. Worth checking for in any consumer repo.
<p> (or <div>) inside an absolutely-positioned pill on top of an image, today using tw-text-h4 for small uppercase. Replacement: swap-class → tw-text-upper. Element stays.<span> with tw-text-h4 near other UI. Replacement: swap-class → tw-text-upper. Element stays.<hN class="tw-text-hM"> where N ≠ M. The class is what the consumer relied on visually. Replacement: swap the class to its new equivalent; element usually stays.<h4 class="tw-lowercase ..."> deliberately removes the H4 uppercase. After the remap H4 isn't uppercase anymore, so tw-lowercase becomes noise. Replacement: swap-both → <p> + tw-text-label (Medium 14px, no transform); drop tw-lowercase.<h4>{{ date }}</h4>. Not really structural; visually small uppercase. Replacement: swap-both → <p> + tw-text-upper.<h4> — semantically not a heading. Replacement: swap-both → <p> + tw-text-upper.tw-text-h4 — small uppercase link. Replacement: swap-class → tw-text-upper. Component element stays.@apply tw-text-h4 overriding third-party iframe styles (e.g. Braintree) — pre-empt the look-shift. Replacement: swap the @apply token to tw-text-upper.<h2 class="tw-text-h4">): decide based on the class — that's what the consumer was relying on visually.<span class="tw-text-h4">): class is the source of truth; element stays unless structurally wrong.@apply tw-text-hN in a <style> block: same per-class decision applies, but the swap is made in the style block (@apply tw-text-upper), not on the template element..tw-text-h1 u { ... }): usually safe to keep — the rules continue to apply to whatever the new mapped style produces. Worth a quick visual check (e.g. underline color/style) but rarely actionable.<h6> and tw-text-h6: in kv-tokens today, tw-text-h6 is not defined (silent no-op) and <h6> has no token-driven base style. Both are off-system — treat as latent bugs to clean up regardless of the remap.defer.When swapping an HTML element (e.g. <h4> → <p>):
class, :class, id, ARIA attributes (aria-labelledby, aria-describedby, etc.), ref, event handlers (@click, etc.), data-*, conditional directives (v-if, v-show).id referenced elsewhere via aria-labelledby, the replacement element still needs that id.</h4> → </p>).querySelectorAll('h4')) and update them — element swaps will break tests that assert on tag names.<hN> and tw-text-hN (redundant), removing the class on element-swap to <p> requires picking the right replacement class — don't leave the <p> typography-naked unless that's intended.@apply swaps in <style> blocks: replace only the matched tw-text-hN token. Do not change the selector or other declarations in the rule.verified? as n/a — no local visual surface with a one-line reason. Should be rare.decision.swap-* row has a non-blank replacement.n/a.rg pattern shows only decision: keep rows remaining.kv-tokens (primitives, configs, classes) as part of this work.tw-text-hN classes.Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub kiva/kv-ui-elements --plugin kiva-design-system