Skip to Content
FrontendBundlesIconsAdding New Icons

Adding New Icons

A practical checklist for what to actually do — and what you can safely skip — when a new icon is added to any mapping.json.

Short answer: nothing breaks if you forget a step below. Worst case, a new icon just isn’t French-searchable yet — it still works exactly like every icon did before this feature existed.

What’s required vs. optional

StepRequired?What happens if you skip it
Add the icon to its mapping.jsonYes (obviously)
Re-run python script/generate-keywords.pyYesThe new icon has no keywords at all — still findable by its English name, just not by French/synonyms
Add words to translations-en-fr.jsonNoThe icon keeps whatever fallback keywords the script can build (see below) — just not French for the untranslated words
Add an entry to keyword-overrides.jsonNoOnly relevant if it’s a brand/product name needing a non-literal synonym (see Keywords & Translations)
Change anything in IconDropdown.tsxOnly for a brand-new icon set folder outside phpc/ — see below

Full worked examples, A to Z

The table above tells you what’s required. These three walk through doing it for real, one per library — every command, every file touched, nothing skipped:

Nothing regenerates automatically. Adding an icon to mapping.json and forgetting to re-run the script leaves the generated files stale — same rule as the pre-existing generate-mapping.py / generate-master-mapping.py scripts in this project.

Adding a whole new icon set

For a brand-new sub-folder (e.g. adding filetypes to glyphicons-v1) or a whole new top-level library — the folder and its mapping.json don’t exist yet.

Verified against src/components/IconDropdown.tsx, script/generate-mapping.py and script/generate-keywords.py in frontend-icons-react-nextjs-bundle (main branch).

How much work depends on two things

IconDropdown.tsx: one import per sub-folder, or one combined file?

glyphicons-v1 imports each sub-folder’s mapping.json by name — one import per sub-folder, forever:

src/components/IconDropdown.tsx
import iconsGlyphiconsV1Basic from "../../icons/glyphicons-v1/basic/mapping.json"; import iconsGlyphiconsV1Filetypes from "../../icons/glyphicons-v1/filetypes/mapping.json";

glyphicons-v2 and phpc each import one file instead, rebuilt by script/generate-mapping.py (step 3 below):

src/components/IconDropdown.tsx
import iconsGlyphiconsV2 from "../../icons/glyphicons-v2/mapping-with-filepath.json"; import iconsPHPC from "../../icons/phpc/mapping-with-filepath.json";

Real constraint, not a style choice: a JS import path has to be written by a person ahead of time — a script that walks the filesystem doesn’t.

generate-keywords.py: hand-written list, or auto-discovered?

Both scripts build a sets list of (mapping.json, ..., keywords.json, ...) entries. glyphicons-v2’s are hand-written, one tuple per sub-folder:

script/generate-keywords.py
("icons/glyphicons-v2/basic/mapping.json", "", "icons/glyphicons-v2/basic/keywords.json", "-"), ("icons/glyphicons-v2/halflings/mapping.json", "", "icons/glyphicons-v2/halflings/keywords.json", "-"),

phpc’s are discovered instead, with no folder name written anywhere:

script/generate-keywords.py
for mapping_path in sorted(glob.glob("icons/phpc/**/mapping.json", recursive=True)): out_path = mapping_path.replace("mapping.json", "keywords.json") sets.append((mapping_path, "", out_path, "-"))

Not a hard limit — glob.glob(...) could replace glyphicons-v2’s 3 tuples too. Nobody has, since 3 lines wasn’t worth automating the way 46 was for phpc. Technical debt, not a constraint.

1. Create the folder

icons/<library>/<subfolder>/, containing the .svg files plus one mapping.json:

icons/ ├─ glyphicons-v1/{basic,halflings,filetypes,socials}/ ├─ glyphicons-v2/{basic,halflings,filetypes}/ ← e.g. a new subfolder here └─ phpc/

2. Normalize mapping.json

Meaning
KeyThe icon’s classname, as shown to the user
ValueThe real icon file name, with extension
icons/<library>/<subfolder>/mapping.json
{ "file-bookmark": "glyphicons-filetypes-89-file-bookmark.svg", "file-stats": "glyphicons-filetypes-31-file-stats.svg" }

glyphicons-v1 bakes the sub-library name into the key twice — e.g. "filetypes filetypes-txt": "icon_uniE001.svg". Every other library uses the plain key above.

If your source data isn’t already in that shape

Raw exports sometimes reverse the key/value roles, or use ligature codes instead of filenames. jq reshapes it fast.

Example — value is a ligature code, not a filename:

{ "glyphicons-txt": "E001", "glyphicons-doc": "E002" }
Turn each value into a real file name

The SVGs are named icon_uni<CODE>.svg, so prepend/append accordingly:

jq 'map_values("icon_uni" + . + ".svg")' mapping.json > new_mapping.json
Strip the redundant prefix from each key
jq 'with_entries(.key |= sub("glyphicons-"; ""))' new_mapping.json > mapping.json

Result:

mapping.json
{ "txt": "icon_uniE001.svg", "doc": "icon_uniE002.svg" }

map_values(...) rewrites every value; with_entries(.key |= sub(...)) rewrites every key. Adapt both filters to your source export.

3. Get the icons into the dropdown

A. glyphicons-v2 or phpc — a new sub-folder under an existing library

Nothing to import by hand — both rebuild from one combined file:

cd icons/ python ../script/generate-mapping.py ./glyphicons-v2 # writes mapping-with-filepath.json — move it into glyphicons-v2/ if it isn't already there

IconDropdown.tsx already imports that file — a new sub-folder is picked up the next time this script runs, no code change:

src/components/IconDropdown.tsx
import iconsGlyphiconsV2 from "../../icons/glyphicons-v2/mapping-with-filepath.json";

Data only. glyphicons-v2 keywords aren’t auto-discovered — see the keywords question above: add a tuple to sets in script/generate-keywords.py, and wire the new keywords.json into v2KeywordSets in IconDropdown.tsx (see Search in IconDropdown). phpc is the only library where both data and keywords are fully automatic.

B. glyphicons-v1, font-awesome, or a genuinely new top-level library

Hardcoded in IconDropdown.tsx: every sub-folder gets its own import plus a manual lookup entry.

Import the new mapping.json (and its keywords.json)
src/components/IconDropdown.tsx
import iconsGlyphiconsV1Filetypes from "../../icons/glyphicons-v1/filetypes/mapping.json"; import iconsGlyphiconsV1FiletypesKeywords from "../../icons/glyphicons-v1/filetypes/keywords.json";
Add it to the library’s lookup objects

One <library>Sets object (the imported mapping) and one matching <library>KeywordSets object, both keyed by "library/subfolder":

src/components/IconDropdown.tsx
const v1Sets = { "glyphicons-v1/basic": iconsGlyphiconsV1Basic, "glyphicons-v1/filetypes": iconsGlyphiconsV1Filetypes, // new // ...other existing entries }; const v1KeywordSets: Record<string, Record<string, string[]>> = { "glyphicons-v1/basic": iconsGlyphiconsV1BasicKeywords, "glyphicons-v1/filetypes": iconsGlyphiconsV1FiletypesKeywords, // new // ...other existing entries };

Add both entries together — the loop right after reads them by the same prefix key, building each IconOption in one pass:

src/components/IconDropdown.tsx
Object.entries(v1Sets).forEach(([prefix, iconSet]) => { const keywordSet = v1KeywordSets[prefix]; Object.entries(iconSet).forEach(([name, path]) => { iconsArray.push({ value: `${prefix}/${name}`, label: name, iconUrl: `${baseUrl}${prefix}/${path}`, keywords: keywordSet?.[name], }); }); });

The access flag is per top-level library, not per sub-folder — canAccessGlyphiconV1 already covers glyphicons-v1/filetypes. A new flag is only needed for a genuinely new top-level library.

Last updated on