inline-style-to-class skill
The inline-style-to-class skill drives /inline-style-to-class. It owns all the behavior described in that command — input parsing, name generation, stylesheet discovery, class emission, file append, source refactoring, and summary output. The command is a thin shell that delegates everything here.
| Triggered by | /inline-style-to-class |
| Allowed tools | Read, Glob, Grep, Bash, Write, Edit, AskUserQuestion |
| Output | A named CSS class appended to the project stylesheet + refactored source with the inline style removed |
Input forms
Section titled “Input forms”| Form | Example |
|---|---|
| HTML inline attribute | <div style="background: var(--surface-1); padding: 1rem"> |
| JSX style object | <Button style={{ backgroundColor: theme.primary, padding: 8 }}> |
<style> block | <style>.hero { color: red; padding: 2rem; }</style> |
Name rules
Section titled “Name rules”- Max 20 characters, kebab-case only (
[a-z][a-z0-9-]*). - If
nameis supplied, it is sanitised in order: lowercase → spaces/underscores replaced with-→ non-[a-z0-9-]characters stripped → leading hyphens and digits stripped → trailing hyphens stripped → consecutive hyphens collapsed → truncated to 20 characters. If the result is empty,AskUserQuestionis used. - If
nameis omitted, the auto-name algorithm runs (see below). Names of 3 characters or fewer triggerAskUserQuestionwith the suggestion pre-filled.
Auto-name algorithm
Section titled “Auto-name algorithm”- If an element tag is present, derive an abbreviation:
button→btn,section→section,header→header,nav→nav,ul/li→list,input→input,img→img,a→link. All other tags use the tag name verbatim (div→div). - From the first declaration in the style source, extract a role hint from the property:
background/background-color/color→bgpadding/padding-*→padmargin/margin-*→gapfont-size/font-weight/font-*→typedisplay/flex/grid→layoutborder/border-*→borderwidth/height/min-*/max-*→sizeposition/top/left/z-index→pos- Any other property — skip the role hint.
- Join with
-:<tag-abbrev>-<role>(e.g.div-bg,btn-pad). If no tag is available, use the role hint alone. - Truncate to 20 characters. Collapse double
-. Strip leading/trailing-. - If the result is empty, use
custom-classand warn. If the result is 1–3 characters, useAskUserQuestionwith the suggestion pre-filled.
Stylesheet discovery
Section titled “Stylesheet discovery”The skill searches for stylesheets in priority order, excluding **/node_modules/**, **/.git/**, **/dist/**, **/build/**:
src/**/*.{css,scss,sass}styles/**/*.{css,scss,sass}app/**/*.{css,scss,sass}*.{css,scss,sass}(repo root)
From the matches, the skill detects syntax flavor (.css, .scss, .sass), indentation (from the first non-empty rule body), and whether the file has a trailing newline.
Selection: exactly one candidate → use it. Multiple candidates with one clear entry file named globals, main, index, styles, app, or base → use that one. Otherwise prompt with AskUserQuestion. No stylesheet found → emit the CSS block to chat only.
Workflow
Section titled “Workflow”-
Parse input. Detect the input form:
- HTML inline attribute — match
style="..."orstyle='...'; split on;; parseproperty: valuepairs. Extract the surrounding element tag if present. - JSX style object — match
style={{...}}; extract the object literal body; convert camelCase keys to kebab-case. Numeric literal values get a “verify unit” warning. JS expression values become/* unresolved: <expr> */placeholders. <style>block — extract content between<style>and</style>; parse rules. If multiple rules are present, ask viaAskUserQuestionwhether to merge all declarations or pick a specific rule.
- HTML inline attribute — match
-
Determine the class name. Apply the name rules. Use the
[name]argument if provided. Otherwise apply the auto-name algorithm. If the generated name is ambiguous or 3 characters or fewer, ask viaAskUserQuestionwith the suggestion pre-filled. -
Discover the target stylesheet. Follow the stylesheet discovery process. Confirm the chosen file with the user only when the choice is ambiguous.
-
Build the CSS class block. Emit using the detected syntax flavor and indentation:
- Comment header:
/* from: <source summary> */(e.g."style attr on <div>","JSX style object","<style> block"). - One property per line.
- Unresolved JSX expressions:
/* <property>: unresolved — was JS expression */. - Numeric values without units: preserve the value and append
/* verify unit */inline. - For Sass-indented (
.sass) syntax, omit braces and use the detected indentation.
- Comment header:
-
Append to the target stylesheet. Use
Editto append the class block, preceded by one blank line. Preserve any trailing newline the file already had. -
Emit refactored source. Produce a clean version of the original input with the inline style removed:
- HTML — remove the
style="..."attribute entirely if all declarations migrated; if some were unresolved, keep only unmigrated declarations in the attribute. Add the new class to the existingclassattribute (or create one). Preserve all other attributes unchanged. - JSX — same logic using
className. Partially-migrated objects preserve remaining key/value pairs in the style prop. <style>block — emit/* rule moved to .<name> in <stylesheet path> */; do not rewrite the<style>block automatically.
- HTML — remove the
-
Print a summary. Reports: class name (provided or auto-generated), any coercion warnings, target stylesheet path and confirmation of append (or a note if no file was found), declaration count migrated, unresolved JS expression count, and numeric-value unit warnings.
JSX camelCase conversion
Section titled “JSX camelCase conversion”JSX style object keys are converted from camelCase to kebab-case before emitting:
// Inputstyle={{ backgroundColor: theme.primary, fontSize: 16 }}
// Output CSSbackground-color: /* unresolved — was JS expression */font-size: 16; /* verify unit */Example output
Section titled “Example output”Given <div style="background: var(--surface-1); padding: 1rem">:
Appended to stylesheet:
/* from: style attr on <div> */.div-bg { background: var(--surface-1); padding: 1rem;}Refactored HTML:
<div class="div-bg"></div>