Here’s a full article draft you can publish, followed by SEO-optimized keywords:
How to Convert ReactSVGIcons JSX into Editable Vectors in Adobe Illustrator
If you’ve ever used ReactSVGIcons or similar libraries, you’ve probably noticed that the generated code isn’t directly usable inside Adobe Illustrator. The problem is that Illustrator requires pure SVG markup, while React icons are exported as JSX functions containing extra JavaScript wrappers like export function …, {...props}, and currentColor.
Trying to paste that code straight into Illustrator won’t work—you’ll see errors like:
“The file temp_reactsvg.svg is in a format which cannot be placed.”
To solve this, we created a custom Adobe Illustrator ExtendScript (JavaScript for Illustrator) that:
- Opens a multi-line dialog where you can paste the raw JSX code.
- Extracts only the
<svg>…</svg>section from the code. - Removes React-specific syntax (
{...props},currentColor, camelCase attributes). - Cleans and rewrites the markup into a valid SVG file.
- Imports it into Illustrator, converting the SVG into editable vector shapes.
- Automatically centers the artwork on your artboard.
The Script
/**
* Illustrator Script: Paste ReactSVGIcons JSX -> clean SVG -> vector
* - Multi-line ScriptUI input
* - Extracts only the <svg>...</svg> section (non-greedy)
* - Removes JSX bits ({...props}, any {...} inside tags)
* - Converts common camelCase SVG attributes to kebab-case (fillRule -> fill-rule, etc.)
* - Removes width/height attributes (so viewBox controls sizing)
* - Ensures xmlns is present
* - Tries to open the SVG file (preferred) and duplicate artwork into the active document,
* otherwise falls back to placing/embedding the SVG.
*/
function main() {
// ScriptUI dialog
var w = new Window("dialog", "Paste ReactSVG / JSX");
w.alignChildren = "fill";
w.add("statictext", undefined, "Paste full ReactSVG/JSX code below:");
var edit = w.add("edittext", [0, 0, 780, 420], "", {multiline: true, scrolling: true});
var btns = w.add("group");
btns.alignment = "center";
var okBtn = btns.add("button", undefined, "OK");
var cancelBtn = btns.add("button", undefined, "Cancel");
okBtn.onClick = function () { w.close(1); };
cancelBtn.onClick = function () { w.close(0); };
if (w.show() !== 1) return;
var input = edit.text;
if (!input || input.replace(/\s/g, "").length === 0) {
alert("No code pasted.");
return;
}
// Extract only <svg ...>...</svg> non-greedy
var svgMatch = input.match(/<svg\b[^>]*>[\s\S]*?<\/svg>/i);
if (!svgMatch) {
alert("No <svg>...</svg> section found.");
return;
}
var svgContent = svgMatch[0];
// --- CLEANUP ---
// 1) Remove JSX spread props {...props} and any other {...} expressions inside tags
// We avoid removing braces that are not in tags by only removing {...} that appear before '>' in an opening tag.
// But simpler & safer: remove all {...} occurrences (React JSX uses them inside tags/expressions).
svgContent = svgContent.replace(/\{\s*\.{3}props\s*\}/g, ""); // remove {...props}
svgContent = svgContent.replace(/\{[\s\S]*?\}/g, ""); // remove any { ... } occurrences
// 2) Convert common camelCase attribute names to kebab-case expected by SVG/XML
var attrMap = {
"fillRule": "fill-rule",
"clipRule": "clip-rule",
"strokeWidth": "stroke-width",
"strokeLinecap": "stroke-linecap",
"strokeLinejoin": "stroke-linejoin",
"strokeMiterlimit": "stroke-miterlimit",
"stopColor": "stop-color",
"stopOpacity": "stop-opacity",
"fontFamily": "font-family",
"fontSize": "font-size",
"gradientTransform": "gradientTransform",
"gradientUnits": "gradientUnits",
"className": "class",
"xlinkHref": "xlink:href",
"xmlnsXlink": "xmlns:xlink",
"fillOpacity": "fill-opacity",
"strokeOpacity": "stroke-opacity",
"textAnchor": "text-anchor",
"enableBackground": "enable-background",
"xmlSpace": "xml:space"
};
for (var k in attrMap) {
// replace only attribute names (word boundary)
var re = new RegExp("\\b" + k + "\\b", "g");
svgContent = svgContent.replace(re, attrMap[k]);
}
// 3) Replace 'currentColor' with a neutral color (Illustrator may not accept currentColor)
svgContent = svgContent.replace(/currentColor/gi, "#000000");
// 4) Remove width/height attributes so viewBox controls scaling (Illustrator dislikes '1em' etc)
svgContent = svgContent.replace(/\s+(width|height)\s*=\s*"[^"]*"/gi, "");
// 5) Ensure xmlns exists (some snippets omit it)
if (!/<svg[^>]*\bxmlns\s*=/i.test(svgContent)) {
svgContent = svgContent.replace(/<svg\b/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
// 6) Ensure xlink namespace if xlink:href used
if (/\bxlink:href\b/i.test(svgContent) && !/\bxmlns:xlink\b/i.test(svgContent)) {
svgContent = svgContent.replace(/<svg\b([^>]*)>/i, function (m, g1) {
return '<svg ' + g1 + ' xmlns:xlink="http://www.w3.org/1999/xlink">';
});
}
// 7) Trim leading/trailing whitespace
svgContent = svgContent.replace(/^\s+|\s+$/g, "");
// 8) Build final SVG text with XML header
var finalSVG = '<?xml version="1.0" encoding="UTF-8"?>\n' + svgContent;
// 9) Save temp file
var tempFile = new File(Folder.temp + "/temp_reactsvg.svg");
tempFile.encoding = "UTF-8";
if (tempFile.exists) {
try { tempFile.remove(); } catch (e) { /* ignore */ }
}
if (!tempFile.open("w")) {
alert("Could not create temporary file: " + tempFile.fsName);
return;
}
tempFile.write(finalSVG);
tempFile.close();
// --- TARGET DOCUMENT (existing or new) ---
var targetDoc;
if (app.documents.length > 0) {
targetDoc = app.activeDocument;
} else {
targetDoc = app.documents.add(DocumentColorSpace.RGB);
}
// Helper: center items within active artboard of targetDoc
function centerItemsOnArtboard(itemsArray, doc) {
if (!itemsArray || itemsArray.length === 0) return;
var minLeft = Number.POSITIVE_INFINITY;
var maxRight = Number.NEGATIVE_INFINITY;
var maxTop = Number.NEGATIVE_INFINITY;
var minBottom = Number.POSITIVE_INFINITY;
for (var i = 0; i < itemsArray.length; i++) {
try {
var b = itemsArray[i].visibleBounds; // [left, top, right, bottom]
if (b[0] < minLeft) minLeft = b[0];
if (b[2] > maxRight) maxRight = b[2];
if (b[1] > maxTop) maxTop = b[1];
if (b[3] < minBottom) minBottom = b[3];
} catch (e) { /* ignore items that fail */ }
}
if (!isFinite(minLeft)) return;
var groupCenterX = (minLeft + maxRight) / 2;
var groupCenterY = (maxTop + minBottom) / 2;
var abIdx = doc.artboards.getActiveArtboardIndex();
var ab = doc.artboards[abIdx].artboardRect; // [left, top, right, bottom]
var artCenterX = ab[0] + (ab[2] - ab[0]) / 2;
var artCenterY = ab[3] + (ab[1] - ab[3]) / 2;
var dx = artCenterX - groupCenterX;
var dy = artCenterY - groupCenterY;
// Move each item by dx, dy
for (var j = 0; j < itemsArray.length; j++) {
try {
var vb = itemsArray[j].visibleBounds;
var curLeft = vb[0];
var curTop = vb[1];
itemsArray[j].position = [curLeft + dx, curTop + dy];
} catch (e) { /* ignore individual move errors */ }
}
}
// --- Try to OPEN the SVG (preferred) and duplicate its pageItems into targetDoc ---
try {
var svgDoc = app.open(tempFile);
// collect duplicated items
var duplicated = [];
// Duplicate every top-level pageItem into targetDoc
// We iterate backwards because duplicating while iterating can reorder indices
var len = svgDoc.pageItems.length;
for (var i = len - 1; i >= 0; i--) {
try {
var pi = svgDoc.pageItems[i];
var newItem = pi.duplicate(targetDoc, ElementPlacement.PLACEATBEGINNING);
duplicated.push(newItem);
} catch (e) {
// ignore duplicate errors for some pageItems
}
}
// Close the temporary svg document without saving
try { svgDoc.close(SaveOptions.DONOTSAVECHANGES); } catch (e) { /* ignore */ }
// Center duplicated items on target artboard
centerItemsOnArtboard(duplicated, targetDoc);
// Optionally: select the duplicated items
try { targetDoc.selection = duplicated; } catch (e) { /* ignore */ }
alert("SVG imported and artwork duplicated into the document.");
return;
} catch (eOpen) {
// Opening failed; fall through to fallback placing method
}
// --- Fallback: place & embed the .svg file into the targetDoc ---
try {
var placedItem = targetDoc.placedItems.add();
placedItem.file = tempFile;
// give Illustrator a moment? (not possible) - try embed
try { placedItem.embed(); } catch (e) { /* ignore embed errors */ }
// Center placed item
centerItemsOnArtboard([placedItem], targetDoc);
alert("SVG placed (embedded) into the document.");
return;
} catch (ePlace) {
alert("Could not place SVG. Error:\n" + ePlace + "\n\nTemp file saved at:\n" + tempFile.fsName);
return;
}
}
main();
How to Use the Script
- Copy the entire JSX export from ReactSVGIcons (e.g.
export function FiletypeJsx...). - Open Illustrator.
- Go to File → Scripts → Other Script… and run the
.jsxfile. - A dialog will appear with a large multi-line input box.
- Paste the full JSX code.
- Click OK.
- The script will automatically:
- Clean the code,
- Generate a valid
.svgfile in your system’s temp folder, - Open it,
- Duplicate the vector paths into your current Illustrator document,
- Center the artwork on the active artboard.
Now you have a fully editable vector icon inside Illustrator!
Why This Script is Useful
- Fast workflow – no need to manually strip JSX or convert with third-party tools.
- Direct vector editing – icons come in as Illustrator shapes, not just embedded objects.
- Scalable – you can paste multiple different icons and repeat the process quickly.
- Reliable – handles attributes like
fillRule,strokeWidth, and converts them to valid SVG.
Final Thoughts
This script is a practical bridge between React icon libraries and Adobe Illustrator’s vector editing power. If you work with design systems or need to convert JSX-based icons into vector assets for branding, UI kits, or print, this solution will save you a ton of time.