Somonor Hong1 downloadsGive folders an icon from the Material Icon Theme, a brand logo or a symbol, right from the file explorer.
Folder icons for the Obsidian file explorer, in the style of VS Code's Material Icon Theme.
Right-click any folder → Change icon…, and pick from three sets:
| Tab | Ids | What it is |
|---|---|---|
| Folders | folder-src, folder-docs, … |
The Material Icon Theme's own folder icons |
| Logos | logo-fastapi, logo-godotengine, … |
A folder in the brand color with the Simple Icons logo as its emblem |
| Symbols | symbol-game, symbol-money, … |
A folder with a Lucide glyph, using the icons Obsidian already ships |
Folders you have not touched can be matched automatically: src, docs, images, .github
and a few thousand other names get the icon the theme would give them. Files can do the same,
by name and extension, if you turn that on.
The ids are the same ones cachewraith-explorer stores, so a folder looks the same in both.
https://github.com/cachewraith-labs/shard-icons.BRAT follows GitHub releases, so it picks up new versions the same way the official installer does.
Download main.js, manifest.json and styles.css from the
latest release into
<your vault>/.obsidian/plugins/shard-icons/, then reload Obsidian.
Once the plugin is accepted, Settings → Community plugins → Browse → Shard Icons.
match.| Setting | Default | What it does |
|---|---|---|
| Automatic folder icons | on | Folders with no chosen icon get one matched from their name |
| File icons | off | Files get an icon from their name and extension |
| Icon size | 16 px | Between 12 and 28 |
| Clear all custom icons | — | Asks first; cannot be undone |
Everything lives in .obsidian/plugins/shard-icons/data.json: your settings and a plain
path → icon id map. Nothing else is stored, and the plugin makes no network requests and
collects nothing.
An icon id this version does not recognise — from a newer release, or from a vault synced the other way — draws a plain folder and is kept, not deleted.
npm install
npm run dev # rebuild main.js on change
npm run build # lint-clean production bundle
npm test
npm run lint
npm run typecheck
To try it in a vault, symlink the repository into the vault's plugin folder:
ln -s "$PWD" "<your vault>/.obsidian/plugins/shard-icons"
Use a scratch vault rather than your real one: Obsidian writes data.json straight into this
folder when the plugin runs.
An Obsidian plugin ships as one main.js, so there is no server to fetch SVGs from.
scripts/build-icons.ts reads material-icon-theme and simple-icons out of node_modules
and writes src/generated/icons.ts: the lookup table, the folder and file SVGs, and the
brand-logo folders it draws itself from the theme's folder shape. That file is generated by
npm run build, npm run dev and npm test, and is git-ignored — the icon packages are the
source of truth, pinned in package-lock.json.
Symbols cost nothing: they are Obsidian's own Lucide icons, fetched at runtime with getIcon.
SHARD_ICONS_FILE_ICONS=0 npm run build leaves the file icons out, which takes the bundle from
about 1.2 MB down to roughly 0.6 MB, at the cost of the File icons setting.
src/
main.ts lifecycle, events and commands — wiring only
icons/ ids, the FolderIcon union, the theme's lookup rules, rendering
explorer/ deciding what each row shows, and putting it there
picker/ the modal
settings/ settings types, validation, the settings tab
store/ path → icon assignments, persisted through loadData/saveData
generated/ build output (git-ignored)
scripts/build-icons.ts
tests/ vitest, no Obsidian required
Everything except icons/render.ts, explorer/FileExplorerIcons.ts, picker/, settings/ SettingsTab.ts and store/IconStore.ts is free of the Obsidian API, which is what lets the
rules be tested directly.
npm version <x.y.z> bumps package.json, then the version script copies that into
manifest.json and records the minimum Obsidian version in versions.json, and npm commits
and tags the three together. The tag is the bare version with no v prefix — that is what
Obsidian expects, and .npmrc sets tag-version-prefix="" so npm does not add one.
npm version 0.2.0
git push --follow-tags
Pushing that tag runs release.yml: lint, tests, build, a
check that the tag matches manifest.json, then a GitHub release with main.js,
manifest.json and styles.css attached. That release is what Obsidian's updater and BRAT
read.
The very first release is the exception — package.json already says 0.1.0, and npm version refuses to set the version it is already on, so tag it by hand:
git tag 0.1.0
git push origin 0.1.0
update-icons.yml bumps the two icon packages weekly,
rebuilds, runs the tests and opens a PR, so new icons arrive on their own. Dependabot handles
the rest of the toolchain.
manifest.json at the repository root with id, name, version, minAppVersion,
description, author, isDesktopOnlyid (shard-icons) and name do not contain "Obsidian" or "plugin"versions.json maps each version to its minimum Obsidian versionmain.js, manifest.json and
styles.css as assetsLICENSE at the repository rootmain.js and src/generated/ are git-ignored, not committedisDesktopOnly: false, and no Node or Electron API in the shipped bundleonunloadcommunity-plugins.jsonThis plugin is MIT (see LICENSE). The icons it bundles are not:
licenses/material-icon-theme-LICENSE.txtlicenses/simple-icons-LICENSE.mdBrand logos are trademarks of their respective owners; the CC0 waiver covers the icon files,
not the marks. See licenses/ for the full notices, which the build copies from
node_modules so they always match the versions in the bundle.