How to automate tailwind svg icon conversion for large icon libraries
- Step 1Fetch the tool schema —
GET /api/v1/tools/svg-to-tailwindwith your API key. The response lists the only option —tailwindMode(enumcurrent/palette, defaultcurrent) — plus the tool's category, output type, and execution mode (engine, runner-executable without a headless browser). - Step 2Install and pair the local runner — Follow the runner docs to install
@jadapps/runner. It listens on127.0.0.1:9789. The JAD/runendpoint is upload-free by design and will answer400 Runner requireduntil you dispatch to the local runner instead. - Step 3Pick the mode for your library — Monochrome icon set that should follow
text-*? UsetailwindMode: "current". Multi-colour icons that should keep distinct colours as Tailwind classes? UsetailwindMode: "palette". There are no other options to set. - Step 4Loop your folder through the runner — For each
.svg, POST{ slug, files|text, options:{ tailwindMode } }tohttp://127.0.0.1:9789/v1/tools/svg-to-tailwind/run. The runner returns the converted SVG text. Write it back next to the source (e.g.<name>-tailwind.svg). - Step 5Safelist the classes Tailwind will need — If consumers apply colour classes dynamically, add them to
safelistin your Tailwind config so JIT/content-scanning doesn't purge them —fill-currentplus anytext-*you set at runtime, or apatternfor palette classes. - Step 6Verify a sample before committing the batch — Spot-check a couple of converted files: confirm
fill="currentColor"+ rootfill-currentforcurrentmode, or the expectedfill-<class>forpalette. Then commit the generated set.
The real API surface (no uploads)
JAD's API returns schema and pairing instructions; execution happens on your local runner. There is no batch/swap-colors endpoint and no per-colour mapping payload.
| Call | Method | What it does |
|---|---|---|
/api/v1/tools/svg-to-tailwind | GET | Returns the tool schema, including the single tailwindMode option |
/api/v1/tools/svg-to-tailwind/run | POST | Returns 400 Runner required + pairing info — never processes content |
http://127.0.0.1:9789/v1/tools/svg-to-tailwind/run | POST | The local runner executes the transform on your machine and returns the SVG |
The only option, and what it produces per icon
tailwindMode is the entire option surface. Anything else you may have seen (color-map.json, convert_all_fills_to_current, multi-map) is not part of this tool.
| tailwindMode | Default | Per-icon result | Best for |
|---|---|---|---|
current | Yes | All colours → currentColor; fill-current on root <svg> | Monochrome libraries that follow text-* |
palette | No | Each colour → nearest Tailwind class (fill-<class>/stroke-<class>) by CIE Lab | Multi-colour sets keeping distinct hues as classes |
Per-colour mapping isn't here — use these instead
svg-to-tailwind has no per-hex mapping. For deterministic colour-to-X mapping across a library, dispatch to a sibling tool in the same loop.
| You want | Tool | Option |
|---|---|---|
| Map specific hex → specific hex | svg-hex-swapper | colorPairs (array of {from,to}) |
| Map colours → named CSS variables | svg-css-variable-injector | variableMap (#hex:--name pairs) |
| Force one solid colour everywhere | svg-monochrome-converter | monochromeMode, monochromeColor |
Cookbook
Real request/response shapes against the JAD API and the local runner.
Fetch the schema
Discover the contract before building payloads. The response confirms the single option and the engine execution mode.
GET /api/v1/tools/svg-to-tailwind
Authorization: Bearer <API_KEY>
{
"slug": "svg-to-tailwind",
"options": [
{ "name": "tailwindMode", "type": "enum",
"values": ["current", "palette"], "default": "current" }
],
"execution": { "runnerMode": "engine" }
}The /run endpoint refuses uploads
Hitting JAD's /run with content returns 400 with pairing instructions. This is intentional — content stays on your machine.
POST /api/v1/tools/svg-to-tailwind/run
400 Runner required
{
"error": "Runner required",
"schemaEndpoint": ".../api/v1/tools/svg-to-tailwind",
"runnerEndpoint": "http://127.0.0.1:9789/v1/tools/svg-to-tailwind/run",
"installRunner": ".../docs/runner"
}Dispatch one icon to the local runner
The runner accepts the same payload shape on localhost and returns the converted SVG text. Here, default current mode.
POST http://127.0.0.1:9789/v1/tools/svg-to-tailwind/run
{
"slug": "svg-to-tailwind",
"text": "<svg viewBox='0 0 24 24'><path d='...' fill='#1a1a2e'/></svg>",
"options": { "tailwindMode": "current" }
}
→ <svg class="fill-current" viewBox="0 0 24 24">
<path d="..." fill="currentColor"/></svg>Loop a folder (palette mode)
Convert every SVG in a directory, keeping per-colour Tailwind classes. Pseudocode over the local runner.
for file in icons/*.svg:
svg = read(file)
res = POST 127.0.0.1:9789/v1/tools/svg-to-tailwind/run
{ slug, text: svg, options:{ tailwindMode:"palette" } }
write("dist/" + basename(file), res.text)
# #4361ee → fill-indigo-600, #ef4444 → fill-red-500, etc.
# (nearest Tailwind class per distinct colour, CIE Lab)Safelist generated classes
Palette mode can emit any of ~244 Tailwind colour classes; current mode emits fill-current. Keep them from being purged.
// tailwind.config.js
module.exports = {
safelist: [
'fill-current',
{ pattern: /(fill|stroke)-(red|blue|indigo|slate|gray)-(400|500|600|700)/ },
],
}Edge cases and what actually happens
There is no /swap-colors or batch endpoint
Invalid endpointOlder guides referenced /api/svg/swap-colors with a color-map.json. That endpoint and payload do not exist for this tool. The real surface is GET /api/v1/tools/svg-to-tailwind (schema) and the local runner's /run; the only option is tailwindMode.
`convert_all_fills_to_current` flag doesn't exist
Invalid optionThere is no convert_all_fills_to_current parameter. The current mode already converts every fill/stroke to currentColor by default — that *is* the behaviour, not an opt-in flag. Sending unknown options has no effect; only tailwindMode is read.
POSTing files to JAD's /run returns 400
400 runner requiredThe JAD /api/v1/tools/.../run endpoint never accepts uploads — it answers 400 Runner required with pairing instructions. This is expected. Dispatch your payload to the paired local runner at 127.0.0.1:9789 instead.
No per-colour mapping in this tool
Not supportedYou cannot say 'map #1a1a2e to fill-current and #4361ee to text-blue-500' through this tool. current flattens everything; palette auto-picks the nearest class per colour. For explicit per-hex control, run svg-hex-swapper or svg-css-variable-injector in the same loop.
Library already uses currentColor (Lucide/Heroicons)
No-opIcons that already ship with currentColor (Lucide, Heroicons) are theme-ready already; the current pass leaves their colours unchanged (currentColor isn't matched) and only ensures fill-current on the root. Reserve the tool for custom/legacy sets with hardcoded hex.
Multi-colour icons collapse in current mode
ExpectedBatch-running current over two-tone icons makes every shape one colour. If the set is meant to be multi-colour, use palette so each colour keeps a distinct fill-<class> — or your icons will all look monochrome after the batch.
Palette emits classes your build hasn't seen
Watch closelypalette can produce any Tailwind colour class. If those exact strings aren't in scanned source, Tailwind purges them and icons render with no colour. Add a safelist pattern covering the hues/shades your library actually maps to.
Rate limit hit on a large run
429 rate limitedSchema fetches are rate-limited; the response carries X-RateLimit-Limit/Remaining/Reset and returns 429 when exceeded. You generally fetch the schema once and then loop locally against the runner, which isn't subject to that API rate limit — so pace schema calls, not runner calls.
Gradients and stop-colors pass through unchanged
PreservedAcross a batch, fill="url(#…)" and <stop stop-color> are left as-is in both modes. Don't expect the batch to theme gradient-based icons; route those to svg-hex-swapper separately.
Frequently asked questions
Is there a batch/upload endpoint for converting many icons?
Not a JAD-hosted one. JAD's API is upload-free: GET /api/v1/tools/svg-to-tailwind gives you the schema and /run returns 400 Runner required. The 'batch' is a loop you run against your paired local @jadapps/runner at 127.0.0.1:9789, which executes the same transform on your machine.
What options can I pass per icon?
Exactly one: tailwindMode, an enum of current (default) or palette. There is no per-colour map, no convert_all_fills_to_current, and no color-map.json. Those don't exist for this tool.
Why does POSTing files to /run give me a 400?
By design — JAD never accepts uploads through its API/MCP layer. The 400 Runner required response includes the runner endpoint and install link. Send the same payload to http://127.0.0.1:9789/v1/tools/svg-to-tailwind/run instead, where it runs locally.
How do I apply consistent colour mappings across the library?
If 'consistent mapping' means flatten-to-currentColor, use current for every icon — it's deterministic. If it means specific hex → specific value, this tool can't do that; pair it with svg-hex-swapper (colorPairs) in the same loop for stable per-hex rewrites.
Does it work with Heroicons, Lucide, or Feather?
Those already use currentColor, so they're Tailwind-ready out of the box and the current pass is essentially a no-op on their colours (it just ensures fill-current on the root). Use this tool for custom or legacy libraries that still bake in hex colours.
How do I keep two colours distinct in a batch?
Use tailwindMode: "palette". Each distinct colour maps to its nearest Tailwind class, so a primary and accent become e.g. fill-slate-800 and fill-indigo-600. current mode would flatten them to one colour.
Will Tailwind purge the classes the batch generates?
It can. Dynamically-applied text-* and palette-mode fill-*/stroke-* classes that aren't literally in scanned source get tree-shaken. Add them to safelist — fill-current plus a pattern covering the colour families your set uses.
Is the runner output identical to the website?
Yes. The runner imports the same engine (runnerMode: "engine" for this tool — no headless browser needed), so a given input + tailwindMode produces the same SVG whether processed in the browser or via the runner.
How do I discover the contract programmatically?
GET /api/v1/tools/svg-to-tailwind. The JSON lists options (just tailwindMode), the outputType, and execution.runnerMode. Build your runner payloads from that rather than hardcoding assumptions.
Do I need a headless browser for this tool?
No. svg-to-tailwind is a pure-text transform (runnerMode: "engine"), so the runner executes it directly without spinning up a browser session — unlike binary-output SVG tools (favicon, app-icon) that need one.
What about gradient-coloured icons in the batch?
They pass through unchanged — url(...) paints and stop-color values aren't matched by either mode. Filter those icons out and route them to svg-hex-swapper if you need their stops recoloured.
Can I emit React components from the batch instead of SVG?
This tool emits SVG. Chain svg-to-jsx or svg-to-vue-svelte after it in your pipeline to wrap each themeable SVG in a component (both default color to currentColor).
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.