zudo-doc
GitHub repository

Type to search...

to open search from anywhere

Footer Taglist

Created Apr 20, 2026Updated Jul 16, 2026Takeshi Takatsudo

Surface the tag vocabulary to readers via an opt-in column block in the site footer.

Overview

The footer taglist is an optional index of tags rendered inside the existing footer grid. It gives readers a persistent way to reach every tag page without leaving the current doc.

It is off by default — the footer looks the same as before until footer.taglist.enabled is set to true in zfb.config.ts. On a fresh scaffold, that setting alone renders an empty taglist: its chrome has no tag loader or vocabulary binding. Nothing about the per-page tag badge row or the homepage "All Tags" section changes.

Enabling

Add a taglist block to the existing footer config:

footer: {
  links: [
    // ...existing footer link columns
  ],
  copyright: `Copyright © ${new Date().getFullYear()} Your Project.`,
  taglist: {
    enabled: true,
    title: "Tags",
    groupBy: "group",
    groupTitles: {
      topic: "By topic",
      type: "By type",
      level: "By level",
    },
    locales: {
      ja: {
        title: "タグ",
        groupTitles: {
          topic: "トピック別",
          type: "種類別",
          level: "レベル別",
        },
      },
    },
  },
},

Each field is optional except enabled. Sensible defaults take over for anything you omit.

Requires tag data bindings

loadTagsForLocale and tagVocabulary default to no-op data. PointchromeBindingsModule at a module that binds both slots. Fresh route stubs already consume it; do not edit them. See Custom Componentsand Host Chrome Bindings.

Add a bindings module that provides the vocabulary and a locale-aware count loader. The loader contract is exactly (lang: string) => readonly { tag: string; count: number }[]; derive its entries from your content collection rather than returning a static list.

src/chrome-bindings.ts
import { defineChromeBindings } from "@takazudo/zudo-doc/chrome-bindings";
import { tagVocabulary } from "./tag-vocabulary";
import { collectTagsForLocale } from "./tag-data";

function loadTagsForLocale(
  lang: string,
): readonly { tag: string; count: number }[] {
  return collectTagsForLocale(lang).map(({ tag, count }) => ({ tag, count }));
}

export const chromeBindings = defineChromeBindings({
  loadTagsForLocale,
  tagVocabulary,
});

Point zudoDoc() at that module and pass the same vocabulary to its build-time tag configuration:

zfb.config.ts
import { defineConfig } from "zfb/config";
import { zudoDoc } from "@takazudo/zudo-doc/config";
import { tagVocabulary } from "./src/tag-vocabulary";

export default defineConfig(
  zudoDoc({
    // ...your settings, including footer.taglist.enabled: true
    tagVocabulary: true,
    tagVocabularyEntries: tagVocabulary,
    chromeBindingsModule: "./src/chrome-bindings.ts",
  }),
);

groupBy: "group" vs "flat"

The taglist can render in two modes.

  • groupBy: "group" — one column per vocabulary group, in the order the groups first appear in the vocabulary you bind. This is the default whenever the vocabulary is active (tagVocabulary: true and tagGovernance !== "off"). Each column's title comes from groupTitles[<group>], falling back to a capitalised version of the group name (topicTopic).

  • groupBy: "flat" — a single alphabetised column titled title. Forced when the vocabulary is inactive, and a useful choice when you have fewer than a handful of tags and grouping would look sparse.

Pick "group" once you have enough tags that a grouped view actually separates topics from types. Stick with "flat" until then.

This repository's src/config/tag-vocabulary.ts is a showcase-only worked example; a fresh scaffold has no src/config/ directory. Create your vocabulary wherever it fits your project and wire it through tagVocabularyEntries and chromeBindings as above.

Locale Overrides

Column titles are the only strings the taglist shows, so locale overrides stay small. The locales map keys on locale code (matching locales in settings):

taglist: {
  enabled: true,
  title: "Tags",
  groupTitles: { topic: "By topic", type: "By type", level: "By level" },
  locales: {
    ja: {
      title: "タグ",
      groupTitles: { topic: "トピック別", type: "種類別", level: "レベル別" },
    },
  },
},

Only keys present in the locale object override the default-locale strings; missing keys fall back. Tag ids themselves are not translated — see the i18n section of the tags guide for the reasoning.

What Readers See

Every vocabulary tag that at least one non-draft, non-unlisted page references appears as a link to that tag's index page (/docs/tags/<id>/ or /{locale}/docs/tags/<id>/). Empty groups collapse — you only pay for the columns you fill.

  • Tag governance — the vocabulary and group declarations that shape the taglist.

  • Tags — the per-page tag badge row and homepage tag index.

  • Footer — the rest of the footer configuration.

Revision History

Takeshi TakatsudoCreated: 2026-04-21T05:26:20+09:00Updated: 2026-07-16T10:13:38+09:00

AI Assistant

Ask a question about the documentation.

Preview theme

Loading theme previews…