svgr
svgr copied to clipboard
prefix the all id attributes with a string, random or customisable
🚀 Feature Proposal
Prepend random, set string to each id
, so that they're unique per this SVG.
Motivation
When you export multiple SVG from let's say Illustrator, you get same id names, for example #b
, #d
and so on. They tend to clash, so I have to manually go to the output of svgr
and prepend some string to each id
value. Can this be automated somehow?
Example
Can we use maybe nanoid
or let's say add an input to the GUI sidebar to prepend that string to each id
?
Pitch
Because in real-life, more often than not, there will be multiple SVG's on a given page, which, in turn, will have to have unique id
s because they're on the same page.
I actually had a similar issue with one of my projects, and I created a plugin to solve it.
You can find my plugin here https://github.com/AlfieJones/theme-toggles/blob/main/packages/react/plugins/babel-plugin-update-id-attribute.js
My plugin adds a prop to each component to allow for an id prefix
@AlfieJones Nice! How cool would it be if the GUI version had this functionality...
I think it is a good addition, let's do it!
@AlfieJones That's a good start but it only updates the ID for clipPath
. URL references for masks, for example, would not work.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Anyone looking for a now solution for this:
I've taken the current version of @AlfieJones plugin, fixed a bug around Hex values:
const t = require("@babel/core").types;
const template = require("@babel/core").template;
const getValueWithProps = (value, { prefix, suffix }) =>
`${prefix ? "${props.idPrefix || ''}" : ""}${value}${
suffix ? "${props.idSuffix || ''}" : ""
}`;
const isHexValue = (possibleHexValue) => {
return (
possibleHexValue[0] === "#" &&
!isNaN(parseInt(possibleHexValue.slice(1), 16))
);
};
const getAttributeValue = (value, opts) => {
let id = "";
let prefix = "";
let suffix = "";
if (value && !isHexValue(value) && value.charAt(0) === "#") {
id = value.slice(1);
prefix = "#";
} else if (value && value.match(/^url\(#/)) {
id = value.slice(5, -1);
prefix = "url(#";
suffix = ")";
}
if (id) {
return t.jsxExpressionContainer(
template.ast(`\`${prefix}${getValueWithProps(id, opts)}${suffix}\``)
.expression,
);
}
};
const getIdValue = (value, opts) =>
t.jsxExpressionContainer(
template.ast(`\`${getValueWithProps(value, opts)}\``).expression,
);
const plugin = (api, opts) => ({
visitor: {
JSXAttribute(path) {
if (!opts.prefix && !opts.suffix) return;
const valuePath = path.get("value");
const namePath = path.get("name");
const value = valuePath?.container?.value?.value;
const name = namePath?.container?.name?.name;
if (name === "id") {
valuePath.replaceWith(getIdValue(value, opts));
} else {
const attr = getAttributeValue(value, opts);
if (attr) {
valuePath.replaceWith(attr);
}
}
},
},
});
module.exports = plugin;
stick it in your svgr config like so:
module.exports = {
// the rest of your config
jsx: {
babelConfig: {
plugins: [
[
path.resolve("./dynamic-ids.js"),
{
prefix: true,
},
],
],
},
},
};
Then you can set a prefix for your IDs via the idPrefix prop on the generated SVG components