Skip to main content

materialx-bookmarks

PyPI Python Tests License

A bookmark list component for mkdocs-materialx. Write your links in YAML, drop one fence into any page, and readers get search, tag filtering, sorting and pagination — no JavaScript to write, no database, no build step of your own.

🔖 Try the live demo →

Search for a typo'd name, stack two tag filters, flip the order, page through — then copy the address bar and see the whole view come back.

Light Dark
A full documentation page in the light theme: site header, navigation sidebar, table of contents, and a bookmark component sitting between two paragraphs of ordinary prose, showing a search box, tag chips with counts, an active git filter, three bookmarks each with labelled link buttons, and centered pagination. The same page in the dark theme, with the component inheriting the theme's colours.

Why

Documentation sites accumulate link lists. Written as plain Markdown they turn into a wall of bullets nobody can search, and keeping them tidy means editing prose. This plugin keeps the data in YAML and the presentation in the theme:

🔍 Fuzzy search Powered by Fuse.js, tolerant of typos, weighted toward titles
🔗 Several links per bookmark Docs, source, changelog — each one a labelled button, or labelled by hostname if you'd rather not
🏷️ Tag filtering Multi-select with AND semantics. Counts follow the current view, and a tag that would return nothing steps aside. Chips sit in your order, alphabetically, or most-used first
🏷️ Your own noun A collection of projects says "Search projects" and "3 of 12 projects", not "bookmarks"
↕️ Sorting Your YAML order, or reversed
📄 Pagination Numbered, configurable page size
🔗 Shareable state Every view is a URL — search, tags, sort and page all round-trip
🧩 Anywhere on any page Mid-article, several per page, as many collections as you like
🎨 Themed automatically Styled entirely with the theme's own CSS variables — light, dark and your accent colour
✅ Validated at build time A typo'd tag or an unknown collection fails the build, not the page
🌍 Translated English and Turkish included, one file to add your own

Quick start

1. Install

pip install materialx-bookmarks

2. Write some bookmarks

Create bookmarks/reading.yml next to your mkdocs.yml:

tags:
  - python
  - rust

bookmarks:
  - title: Ruff
    description: Linter and formatter for Python, written in Rust.
    tags: [python, rust]
    links:
      - text: Docs
        url: https://docs.astral.sh/ruff/
      - text: GitHub
        url: https://github.com/astral-sh/ruff

  - title: ripgrep
    description: Recursively searches directories for a regex pattern.
    tags: [rust]
    links:
      - url: https://github.com/BurntSushi/ripgrep

3. Register the collection

plugins:
  - materialx-bookmarks:
      collections:
        - name: reading
          file: bookmarks/reading.yml

4. Drop it on a page

# My reading list

Things worth coming back to.

```bookmarks
collection: reading
```

That's it. mkdocs serve, and editing the YAML live-reloads the page.


Reference

Bookmark files

tags: [python, rust]        # allowlist — a bookmark may only use tags listed here

bookmarks:
  - title: Ruff             # the only required field
    description: …          # optional
    tags: [python]          # optional
    links:                  # optional — each entry needs a url
      - text: Docs          # optional — without it the button shows the hostname
        url: https://…

Bookmarks appear in the order you write them. The tags allowlist is what turns a misspelled tag into a build error instead of a chip nobody ever clicks.

Links render as buttons under the description, in the order you write them. A bookmark with no links renders as plain text.

Plugin options

plugins:
  - materialx-bookmarks:
      language: en
      collections:
        - name: reading
          file: bookmarks/reading.yml
          per_page: 20
Option Required Default Description
language no theme.language, else en Language for the interface strings
collections[].name yes — The name pages refer to. Must be unique
collections[].file yes — Path to the YAML file, relative to mkdocs.yml. Keep it outside docs/ so it is not copied into the built site
collections[].per_page no 20 Bookmarks per page
collections[].item_name no the language's own word Singular noun for one entry, e.g. project
collections[].item_name_plural no the language's own word Plural noun, e.g. projects. Required together with item_name
collections[].tag_sorting no manual Tag chip order: manual, alphabetical or count

Naming what a collection holds

By default the interface says "bookmarks" — "Search bookmarks", "3 of 12 bookmarks". A collection that holds something else can say so:

collections:
  - name: projects
    file: bookmarks/projects.yml
    item_name: project
    item_name_plural: projects

The nouns go into every string that needs one: Search projects, No projects found, 3 of 12 projects, and 1 of 1 project when a single entry matches. Give both keys or neither — the plugin will not guess a plural. Leave them out and each language supplies its own word, so a Turkish site reads "Yer işaretleri içinde ara" without any configuration.

Ordering the tag chips

collections:
  - name: tools
    file: bookmarks/tools.yml
    tag_sorting: count
manual The order the tags are written in the collection's YAML. The default
alphabetical Sorted under the site's language, so Turkish ı lands where a Turkish reader expects it
count Most-used tag first, ties keeping the YAML order. The counts follow the current view, so the chips re-order as the reader searches and filters

Placing components

A page may hold as many components as you like. Give a fence an id when two of them would otherwise collide:

```bookmarks
collection: reading
id: reading-secondary
```
Key Required Description
collection yes Name of a collection from mkdocs.yml
id no Defaults to the collection name. Namespaces this component's URL parameters

URL state

Every control writes to the address bar, namespaced by component id, so a filtered view can be linked to and returns intact:

?reading.q=ruff&reading.tags=python,rust&reading.sort=reversed&reading.page=2

How it works

At build time the plugin reads your YAML, validates it, and writes one JSON file per collection into the site. Each fence becomes an empty container carrying its configuration. Anything wrong — a missing file, a bookmark without a title, a tag outside the allowlist, a fence naming a collection that does not exist — stops the build with a message naming the file and the entry.

In the browser a small bundle (about 30 KB including Fuse.js) fetches that JSON once per collection and renders the list. Assets are emitted under content-hashed filenames, so upgrading the plugin never leaves a visitor on a stale bundle.

Controls are real buttons with aria-pressed, the search box is labelled, the result count is a live region, and pagination sits in a landmark nav — all of it keyboard reachable.


Languages

English (en) and Turkish (tr) ship with the plugin, and the language follows your theme.language unless you set one. Adding another is a single file — see CONTRIBUTING.md.

Requirements

Python 3.10+, MkDocs 1.5+, and the mkdocs-materialx theme.

Contributing

Tests, the demo site and the release workflow are described in CONTRIBUTING.md.

License

MIT

Metadata

Release files for materialx-bookmarks 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for materialx-bookmarks 0.4.0
File Size Uploaded
materialx_bookmarks-0.4.0.tar.gz 38.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for materialx-bookmarks 0.4.0
File Interpreter ABI Platform
materialx_bookmarks-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 65.9 kB

Release files / materialx_bookmarks-0.4.0.tar.gz

Download URL materialx_bookmarks-0.4.0.tar.gz
Size 38.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2f4cc4da77460bf80a4b4b2dfd30f40cee66035e333aefa20fe05723bff12283
BLAKE2b-256 checksum
How to use checksums
5c1936afed28bb82cdbc64b05593ee2970fd2099083a4213902937334ebdb967
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release files / materialx_bookmarks-0.4.0-py3-none-any.whl

Download URL materialx_bookmarks-0.4.0-py3-none-any.whl
Size 27.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6083a672447b7df49bc6790a6b843e3a157e6a018ee2aa28c52e092927f0f26e
BLAKE2b-256 checksum
How to use checksums
3d53bb648c423d006757e7dc2d4dd8d49dff44b38c06f8dbf3c95efc1d05f036
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page