Html to component
Skill vipincode/exr-agent-skills/.claude/skills/html-to-component
Agent Skills for building production-grade Express + TypeScript + Mongoose backends with Claude Code
npx -y skills add vipincode/exr-agent-skills --skill html-to-componentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Turn an HTML file, a pasted HTML section, or a live URL into a production-grade Next.js + TypeScript + Tailwind + shadcn/ui design — in two phases. (1) THEME — extract the design's tokens (colors → oklch, typography, fonts, radius, shadows, spacing, gradients, background images) and apply them to globals.css + wire fonts in layout.tsx. (2) COMPONENTS — turn the markup into components WITHOUT creating duplicates, scanning MODULE_REGISTRY.md and the shared/feature trees first and reusing/extending what exists, placing generic pieces (header, navbar, hero, small-hero, carousel, charts, sidebar, avatar, logo, banner …) in components/shared and domain-specific ones in features/<name>/components, styling with Tailwind utilities + theme tokens, animating with Tailwind/CSS or framer-motion, and registering new shared components. Use this whenever the user wants to convert/implement/build HTML into React/Next.js — phrases like "turn this HTML into a component", "build this html section", "convert design.html to next.js", "code this markup", "html to react/next", or when they point at an .html file (often in _docs/designs/) or paste a chunk of HTML/CSS and want components. Looks for design files in _docs/designs/ by default. Builds INTO an existing Next.js + shadcn project (scaffold first with nextjs-bootstrap; this skill does NOT scaffold). It is the HTML counterpart to figma-to-component (source = Figma) and project-to-component (source = an existing codebase/repo on disk) — reach for those when the source isn't an HTML file/section/URL.
SKILL.md
17.2 KB, as published. Nobody here has run it
html-to-component
Convert HTML (a whole page, a pasted section, or a fetched URL) into Next.js + Tailwind + shadcn/ui that looks production-grade and fits the project's existing structure. It does two jobs in order: first it lifts the design's tokens into the theme (colors in oklch, fonts, radius, shadows, spacing, gradients) so everything downstream is token-based; then it turns the markup into components without creating duplicates — the headline being no duplicate Header, no second Avatar, no third Card.
The hard part isn't generating JSX from HTML — current models do that well. The hard parts are: (a) not hardcoding the raw #3B82F6/14px/box-shadow the HTML is full of, but routing them through a real theme; and (b) not re-emitting the same header/card/avatar inline on every section. So this skill is built around a theme-first, then dedup-first discipline.
This is a builder skill. It assumes the project is already scaffolded (nextjs-bootstrap) — it builds into that structure. It does not scaffold.
The two core problems this skill solves
- Raw values everywhere. HTML/CSS hands you literal hex, px, rgba shadows, inline styles, or baked-in Tailwind arbitrary values (
bg-[#3B82F6],text-[14px]). Shipped as-is, the redesign never survives and shadcn components stay unthemed. The fix: extract the recurring values as tokens and write them where a shadcn app stores its theme —globals.css(colors in oklch) andlayout.tsx(fonts) — then style components withbg-primary/rounded-lg/shadow-card, never the raw value. - Designs repeat. The same header sits on five sections, avatars and cards are everywhere. A naive markup→code pass re-emits each inline and the codebase fills with duplicates. The fix: treat
MODULE_REGISTRY.mdas a dedup ledger and the shared/feature trees as the source of truth — before writing any component, check whether it already exists; reuse it, extend it, or only then create it, and put reusable ones incomponents/shared/so the next section reuses them. Readreferences/dedup-protocol.md; it's the heart of phase 2.
Prerequisites & resolution
- Resolve the project dir. Read
.claude/workspace.json(repo root) →frontendentry =<proj>. Else find afrontend-*folder (e.g.frontend-shoply/), a plainfrontend/, or asrc/app/with shadcn (globals.css+components/ui/). If there's no scaffolded Next.js + shadcn project, stop and point atnextjs-bootstrap— this skill builds into an existing structure, it doesn't create one. - Read the contract files (required):
ARCHITECTURE.md(conventions) andMODULE_REGISTRY.md(the dedup ledger — every existing shared component, hook, util). You cannot dedup against a ledger you haven't read. - Resolve the HTML input. In priority order: an explicit path the user gave → a pasted HTML block in the message → a URL (fetch it) → scan
_docs/designs/(the project's design drop-folder) and use/confirm the relevant file. If the HTML links external CSS (<link rel="stylesheet">) or fonts, read those files too — the styling lives there. Seereferences/reading-html.md. - Determine the package manager (
pnpm/npm/yarnfrom the lockfile) for shadcn/build commands below.
Decide the scope (which phases to run)
- A whole page / a fresh design, or the project still has the stock shadcn theme → run Phase 1 (theme) then Phase 2 (components).
- A single section/snippet on an already-themed project → Phase 2 is the focus, but still scan the snippet for new tokens (a brand color or font not yet in the theme). Don't hardcode them — append them to the theme (a light Phase 1 pass) and then reference them. Surface to the user when you add a token.
- The user explicitly asks for only theming or only a component → do just that phase. Stay in scope.
State which phases you'll run before you start, so the user can redirect.
Phase 1 — Theme (tokens → globals.css + layout.tsx)
Skip or trim per the scope decision above. Paths are relative to
<proj>.
- Extract the tokens from the HTML. Pull every recurring color, font-family, font-size/line-height, font-weight, radius, shadow, spacing step, gradient, and background image out of the
<style>blocks, linked CSS, inlinestyle=attributes, and any baked-in Tailwind classes. Runscripts/extract_tokens.py <file>to get a frequency-sorted inventory fast, then read it with judgment — recurring values are tokens; one-offs belong to a component, not the theme. Seereferences/reading-html.md("Extracting design tokens"). - Normalize into a token map. Group into: colors (→ shadcn roles), typography (families + the size/line-height/weight scale), radius, shadows, spacing, gradients, background images. Map the design's colors onto shadcn's semantic roles rather than inventing names (so every shadcn component is themed for free). See
references/theme-tokens.md. - Convert every color to oklch. Collect the values into
{role: "#hex"}and runpython scripts/hex_to_oklch.py --json colors.json. Use the output verbatim — shadcn/Tailwind v4 store theme colors as oklch; never paste raw hex into theme variables. - Rewrite
globals.css— light AND dark. Update the:root(light),.dark(dark), and@theme inlineblocks — re-value the roles, don't rename them. shadcn themes are dual-mode: if the HTML defines a dark variant (.dark/[data-theme="dark"]block,prefers-color-scheme: darkmedia query, ordark:Tailwind variants) capture that palette into.dark; if it's single-mode, fill the given mode and derive the other (don't leave stale shadcn defaults) and say you derived it. Set--radius, add--shadow-*, gradient tokens, and any custom type-scale entries.references/theme-tokens.mdhas the exact block shapes and the dark-derivation rules. - Wire fonts in
layout.tsx. Google families vianext/font/google, custom/brand files vianext/font/local(drop files undersrc/app/fonts/). Each font exposes a CSS variable; add them to<html className>and bind them in@theme(--font-sans,--font-display, …). Never<link>tags or@import url(). Seereferences/fonts.md. - Apply the rest as tokens. Radius, shadows, gradients, background images → tokens/utilities so components reference
rounded-lg,shadow-card,bg-[image:var(--gradient-brand)], never raw values. - Update the contract files. In
ARCHITECTURE.md, make the theme concrete (fonts used, palette source = this HTML, oklch). InMODULE_REGISTRY.md, log the theming decision.
Phase 2 — Components (the dedup-first build)
Paths relative to
<proj>. Conventions come fromARCHITECTURE.md+ the references below; project docs win on project-specifics.
- Map the structure before coding. Read the HTML top-down. Semantic tags (
<header>,<nav>,<main>,<section>,<footer>,<aside>) and class names (hero,card,navbar,avatar) are your decomposition map and dedup hints — the HTML analog of Figma layer names. List the discrete pieces. For a big page, outline the sections first, then drill into each. Seereferences/reading-html.md. - Classify each candidate piece reusable-generic vs feature-specific using
references/shared-taxonomy.md. A block that is a header/navbar/hero/carousel/chart/sidebar/avatar/logo/banner is almost always a shared component. - Run the dedup protocol for every candidate (
references/dedup-protocol.md): checkMODULE_REGISTRY.md→ grepcomponents/shared,components/ui,features/*/components→ decide reuse / extend / create. Never create something the ledger already lists. If a feature-local component is now needed by a second feature, move it to shared (don't copy). The protocol covers non-component reusables too — utils, hooks, types, constants get the same search (lib,hooks,src/types,src/constants) and the same placement-by-dependency rule, so design-time code lands wherefrontend-module-builderexpects it. - Fill primitive gaps via shadcn, not by hand. If a piece is really a primitive the project lacks (
carousel,avatar,chart,tabs,accordion,sidebar, …), add it with<pm> dlx shadcn@latest add <name>intocomponents/ui/and compose it — never hand-author or re-skin a primitive. - Build each new component — mobile-first and token-based. Tailwind utility classes only (no separate CSS files; no inline
style={{}}for things Tailwind covers); reference theme tokens (bg-primary,text-muted-foreground,rounded-lg,shadow-card,font-display) instead of the raw hex/px in the source HTML — never a hardcoded color when a token exists. Author mobile-first: base classes target small screens, layer up withmd:/lg:prefixes; honor the source's@mediaqueries via breakpoints, and infer the mobile layout when the markup is desktop-only. Any header/navbar/sidebar collapses on mobile into a hamburger that opens a shadcnSheet. Match spacing, gap, radius, border, shadow, line-height faithfully — through the token system, responsively (don't pin desktop px). TypeScript props;cvafor variant-bearing components. Reusable →components/shared/<group>/; domain-specific →features/<name>/components/. Seereferences/building-components.md. - Assets & icons. For
<img>/background images in the HTML: copy local asset files intopublic/(or the feature) and usenext/image; for remotesrcURLs, download intopublic/rather than hotlinking. Icons come from the single registry filecomponents/shared/icons.tsx(lucide-react first, react-icons for gaps, customcurrentColorSVGs last) — map source icon fonts/inline<svg>s to lucide equivalents and import from the registry, never from the icon library directly. Seereferences/building-components.md("Assets", "Icons"). - Animation. Default to Tailwind/CSS transitions and shadcn's built-in motion; reach for framer-motion (
motion/react) only for orchestrated/gesture/scroll-linked motion. Translate CSStransition/@keyframes/animationin the source to the equivalent. Seereferences/animation.md. - Compose & register. Assemble the pieces into the screen via a feature
template/if it's a full screen; keeppage.tsxthin. Register every new shared component inMODULE_REGISTRY.md(name, path, what it wraps, purpose) — an unregistered shared component is a future duplicate. - Verify.
<pm> run build(typecheck + lint) and a quick read-through against the source HTML. Report: theme changes (if Phase 1 ran), components created vs reused, where each landed, primitives added, registry rows added.
What to read when
references/reading-html.md— how to read the input (file / pasted / URL /_docs/designs), resolve linked CSS & fonts, parse structure for decomposition, and extract design tokens from plain CSS, inline styles, and baked-in Tailwind. Read before Phase 1 step 1 and Phase 2 step 1.references/theme-tokens.md— shadcn role table, color→role mapping, the exact Tailwind v4:root/.dark/@theme inlineblock shapes, and radius/shadow/gradient/bg-image tokens. Read during Phase 1 steps 2–6.references/fonts.md—next/font/googleandnext/font/localpatterns, exposing & binding CSS variables, handling the families the HTML uses. Read during Phase 1 step 5.references/dedup-protocol.md— the reuse/extend/create decision and the exact search order. Read before creating any component. This is the skill's reason to exist.references/shared-taxonomy.md— reusable-shared vs feature-specific, the canonical shared list (header, navbar, hero, small-hero, carousel, charts, sidebar, avatar, logo, banner …) and whichcomponents/shared/subfolder each lands in. Read during Phase 2 step 2.references/building-components.md— Tailwind-token styling rules,cva, server vs client, props/typing, faithful spacing/shadow/radius via tokens, assets/next/image, accessibility. Read before Phase 2 step 5.references/animation.md— Tailwind/CSS vs framer-motion decision and patterns; translating CSS animation from the source. Read before Phase 2 step 7 (only if the design animates).scripts/extract_tokens.py— scans an HTML/CSS file and prints a frequency-sorted inventory of colors, font-families, font-sizes, radii, shadows, gradients. Run it first in Phase 1.scripts/hex_to_oklch.py— hex/rgb →oklch()converter (single, many, or--jsonbatch). Use it for every color.
Non-negotiables (why this skill exists)
- Colors are oklch, tokens not raw values. Recurring colors become shadcn role tokens in
globals.css, converted with the script. A component shippingbg-[#3B82F6]ortext-[14px]when a token exists defeats the theme and the next redesign. Always use the token — translate raw HTML values tobg-primary/text-sm/rounded-xl/shadow-card, never a hardcoded color. - Mobile-first responsive, with a real mobile nav. Every component is authored mobile-first (base = small screen,
md:/lg:layer up), never desktop-pinned to the mockup's fixed width. Any header/navbar/sidebar collapses on mobile into a hamburger that opens a shadcnSheet— not links silentlyhiddenwith no affordance. - Check the registry before you create — every time. The
MODULE_REGISTRY.mdledger + a grep ofshared/ui/featuresis mandatory per candidate component. Re-creating something that exists is the exact failure this skill prevents. Reuse > extend > create. - One home per component, by dependency. Generic/reusable →
components/shared/<group>/. Depends on one feature's domain →features/<name>/components/. A reusable component buried in a feature folder is a bug; so is a domain component in shared. When a feature-local piece is needed by a second feature, it moves to shared and gets registered — never copied. The same placement-by-dependency applies to non-components: utils →lib/, hooks →hooks/, multi-feature types →src/types/, multi-feature constants →src/constants/. - shadcn primitives are composed, never duplicated. Need a carousel/avatar/chart/tabs/sidebar?
shadcn addit and wrap it. Hand-writing a primitive shadcn ships, or forking a styled sibling ofButton/Select, is a regression. When the design's primitive looks different, edit itscvavariants in place (seereferences/building-components.md"The design's variants live inui/") — that's the sanctioned path. - Don't restructure shadcn's theme — re-value it. Keep the role names and the
:root/.dark/@theme inlineshape; swap values and add tokens. Fonts go throughnext/font, never<link>/@import. - Always produce both light and dark. shadcn's theme is dual-mode. Capture the design's dark palette when it has one; derive it when it doesn't. Every role in
:rootmust also exist in.dark— a missing role is an unthemed component in dark mode. Leaving stock shadcn dark defaults under a custom light theme is the failure to avoid. - Reusable shared components get registered immediately. A new
Header/Avatar/Carouselincomponents/shared/that isn't inMODULE_REGISTRY.mdis invisible to the next run and will be rebuilt. - Faithful, but production-grade. Honor the design's spacing, gaps, radii, borders, shadows, gradients, line-heights — through tokens, responsively (mobile-first, not desktop-pinned). Semantic markup, alt text, focus states. The output should look like a senior engineer built it, not like converted markup.
- Stay in your lane. Build into the existing structure. Don't scaffold (that's
nextjs-bootstrap). When the source is Figma, usefigma-to-componentinstead.