Jesus1 downloadsShow the number of files and subfolders contained in each folder in the file explorer.
An Obsidian plugin that shows the number of files and subfolders contained in each folder, right next to the folder name in the file explorer.
The count can be styled from the plugin settings or with a CSS snippet.
Under Settings → Folder Child Count → Appearance:
| Setting | What it does |
|---|---|
| Use a custom color | Use your own color instead of the theme's muted text color. |
| Color | The color to use (shown when "Use a custom color" is on). |
| Style | Badge (default), Plain text (no background) or Outline. |
| Size | Small, Normal or Large. |
| Bold | Render the count in bold. |
| Show only on hover | Reveal the count when hovering the folder row (desktop only). |
Create <your-vault>/.obsidian/snippets/folder-count.css and enable it under
Settings → Appearance → CSS snippets:
.folder-child-count {
color: var(--text-accent);
background-color: transparent;
font-weight: 600;
font-family: var(--font-monospace);
font-size: 0.7em;
}
/* Reveal the count only while hovering a folder */
.nav-folder-title .folder-child-count {
opacity: 0;
transition: opacity 120ms ease-in-out;
}
.nav-folder-title:hover .folder-child-count {
opacity: 1;
}
By default the badge uses Obsidian's CSS variables, so it follows your theme without extra effort.
.nvmrc).The plugin's settings tab is built with Obsidian's declarative settings API
(getSettingDefinitions, available since 1.13.0), which keeps the settings
searchable and avoids the deprecated imperative display() method. If you need
to support older app versions, you can lower minAppVersion in manifest.json
and add a display() fallback that renders the same options with new Setting().
This project uses TypeScript and esbuild.
# Install dependencies
npm install
# Compile and watch for changes (development)
npm run dev
# Run the unit tests
npm run test
# Type-check and produce a production build
npm run build
# Lint the source
npm run lint
The built plugin must live in the vault's plugins folder:
<your-vault>/.obsidian/plugins/folder-child-count/
There is a helper script that builds the destination folder and links the
required files (main.js, manifest.json, styles.css) for you:
npm run build
npm run install:vault -- /path/to/your/vault
# or set the path once:
OBSIDIAN_VAULT=/path/to/your/vault npm run install:vault
# copy real files instead of symlinks:
npm run install:vault -- /path/to/your/vault --copy
By default the files are symlinked, so npm run dev rebuilds are picked up
as soon as you reload Obsidian (Ctrl/Cmd + R). Then enable the plugin under
Settings → Community plugins.
.
├── src/
│ ├── main.ts # Plugin entry point, file-explorer integration, observers
│ ├── badge.ts # Renders the count badge in a folder title
│ ├── settings.ts # Settings interface, defaults and settings tab
│ └── folder-count.ts # Pure counting logic
├── tests/
│ ├── folder-count.test.ts # Unit tests for the counting logic
│ ├── badge.test.ts # DOM tests for the badge (jsdom)
│ ├── plugin.test.ts # Integration tests for main.ts + observers
│ ├── helpers.ts # Test factories for folders/files
│ ├── obsidian-mock.ts # Runtime stub for the types-only obsidian package
│ └── setup-dom.ts # jsdom shim for Obsidian's DOM helpers
├── .github/ # CI, release workflow, templates and FUNDING
├── esbuild.config.mjs # Build configuration
├── vitest.config.ts # Test configuration
├── manifest.json # Obsidian plugin manifest
├── styles.css # Badge styling
└── versions.json # Version -> minimum app version map
Tests run with Vitest in a jsdom environment. The
obsidian package only ships type declarations, so:
vitest.config.ts aliases obsidian to tests/obsidian-mock.ts, a tiny
runtime stub exposing the classes the source imports.tests/setup-dom.ts shims the handful of Element.prototype helpers Obsidian
adds (createSpan, createDiv, setText) so badge.ts runs under jsdom.npm run test # run once
npm run test:watch # watch mode
.github/workflows/ci.yml runs lint, tests and build on pushes and pull
requests..github/workflows/release.yml builds and publishes a GitHub release when a
tag is pushed (the tag must match manifest.json's version).Update the version with npm version patch|minor|major (this runs
version-bump.mjs to keep manifest.json and versions.json in sync).
Tag and push. The release workflow builds, attests and publishes:
npm version patch # updates manifest.json + versions.json
git push --follow-tags
npm version also commits the bumped manifest.json/versions.json and
creates the tag. Tags are unprefixed (.npmrc sets tag-version-prefix=),
e.g. 1.0.1 rather than v1.0.1.
.github/workflows/release.yml runs the tests and build, generates a signed
build provenance attestation (GitHub Artifact Attestations, backed by
Sigstore) plus a SHA256SUMS file, and creates the release with main.js,
manifest.json, styles.css and SHA256SUMS.
Attestations are keyless and bound to this repository's release workflow. Anyone can verify that a downloaded asset was produced by this repo's CI from the tagged commit:
gh attestation verify main.js --repo <owner>/<repo>
gh attestation verify manifest.json --repo <owner>/<repo>
gh attestation verify styles.css --repo <owner>/<repo>
A successful check means the file's digest matches the attested build and that
the provenance was issued by a workflow in that repository. For an additional
layer of trust you can also sign the release tags with GPG (git tag -s v1.0.0).
Each release also ships a SHA256SUMS file (generated with npm run checksums).
Verify the downloaded artifacts against it:
# Linux
sha256sum --check SHA256SUMS
# macOS
shasum -a 256 --check SHA256SUMS
An authorized security self-assessment (source review, dependency audit,
supply-chain review and secret scanning) is documented in
pentest/final-report.md.
See CONTRIBUTING.md for the development setup and guidelines.