Navigation

How OpenAPI tags, paths, models, and webhooks become browsable docs.

printing press builds navigation from the OpenAPI contract itself.

That means the sidebar, overview page, operation breadcrumbs, tag pages, model groups, and webhook section all come from the same rendered documentation model. There is no second navigation file to keep in sync. The spec owns the shape, and printing press turns that shape into stable pages.

The navigation model is composed from:

  • root-level OpenAPI tags
  • operation tags
  • operation paths and operation IDs
  • component models
  • webhooks
  • diagnostics counts, when diagnostics mode is enabled
The best navigation comes from well-authored tags. The fallback logic exists so incomplete or coarse specs still render into something useful.

OpenAPI 3.2 hierarchical tags

OpenAPI 3.2 allows tags to describe hierarchy. printing press reads parent relationships from the root tags list and builds a tree from them.

Use this when the API already has a product, domain, or workflow structure:

openapi: 3.2.0
info:
  title: Travel API
  version: 1.0.0
tags:
  - name: Travel
    summary: Travel
    kind: nav
  - name: Bookings
    summary: Bookings
    parent: Travel
    description: Booking lifecycle operations.
  - name: Payments
    summary: Payments
    parent: Travel
    description: Payment capture and refund operations.
paths:
  /bookings:
    get:
      tags:
        - Bookings
      summary: List bookings
      operationId: listBookings
      responses:
        "200":
          description: OK

In that shape, Travel is the parent navigation group. Bookings and Payments are child groups. Operations tagged with Bookings appear under the Travel > Bookings path and get breadcrumbs back through that same hierarchy.

kind: nav marks a tag as a grouping node. Use it for a parent that exists to organize the docs, not to own operations directly.

Each tag also gets its own generated tag page under tags/*.html. If the tag has a markdown description, that description is rendered on the tag page before the operation list.


OpenAPI 3.1 flat tags

OpenAPI 3.1 tags are flat, and printing press treats them that way.

openapi: 3.1.0
info:
  title: Travel API
  version: 1.0.0
tags:
  - name: Bookings
    description: Booking lifecycle operations.
  - name: Payments
    description: Payment capture and refund operations.
paths:
  /bookings:
    get:
      tags:
        - Bookings
      summary: List bookings
      operationId: listBookings
      responses:
        "200":
          description: OK

The root tags list defines the visible operation groups. Operations are assigned by tag name, so the value in operation.tags should match the root tag name.

If a root tag is declared but never receives an operation or child tag, printing press removes it from the rendered navigation. Empty placeholders do not clutter the docs.


Slug matching and stable URLs

Every generated page gets a URL-safe slug.

Tag names, operation IDs, model names, and synthetic path groups are normalized into lower-case, kebab-case URL segments. Long slugs are bounded, and collisions get a numeric suffix so pages stay addressable.

Operations prefer operationId for their page slug:

operationId: listBookings

That becomes:

operations/list-bookings.html

If there is no operationId, printing press falls back to the HTTP method and path.

Stable operation IDs are the cleanest way to keep links durable across releases. Tag slugs and model slugs follow the same URL-safe rules, so generated links work in static, published, and served output.

Inside the rendered docs, those slugs become the matching key for navigation state. The current operation or model slug opens the right group, marks the active link, and connects breadcrumbs back to generated tag, operation, and model pages.


Path fallback

Some specs use no operation tags. Others use one or two broad tags across a large API, which makes the sidebar almost useless.

When tags are missing, unknown, or too coarse, printing press composes operation navigation from path patterns.

It reads the first meaningful path segments and turns them into navigation groups:

/v1/accounts/{accountId}/transactions

becomes:

Accounts > Transactions

Version prefixes like v1, path parameters like {accountId}, and action-only segments like get, list, create, update, and delete are skipped so the navigation stays resource-focused.

When a path group has multiple useful second-level segments, printing press creates a parent and child structure. When there is only one useful segment, it stays flat.


Coarse tag fallback

Large APIs sometimes tag every operation with the same vendor, product, or umbrella tag.

For that shape, printing press can treat the API as effectively untagged and reuse the same path-pattern grouping. By default, this happens when a spec has enough operations and only a very small number of distinct operation tags.

So a large spec that tags everything as:

tags:
  - name: plaid
paths:
  /accounts:
    get:
      tags:
        - plaid
  /transactions:
    get:
      tags:
        - plaid

can render as:

Accounts
Transactions

instead of one giant plaid bucket.

This is not a replacement for good tags. It is a safety net for specs that were authored for validation, not for docs.


Models and webhooks

Operation tags are only one part of the navigation.

printing press also builds a model section from OpenAPI components. Schemas, responses, parameters, request bodies, headers, security schemes, examples, links, and callbacks are grouped by component type when they exist.

Webhooks are rendered as their own navigation section, separate from request-response operations.

The result is one sidebar with:

  • API overview
  • diagnostics, when diagnostics mode is enabled
  • operations
  • models
  • webhooks

Authoring guidance

Use OpenAPI 3.2 hierarchical tags when the API has a real information architecture.

Use OpenAPI 3.1 flat tags when the API is smaller, or when a single operation group is enough.

Keep root tag names and operation tag values identical. summary is a better place for a cleaner display label.

Prefer stable operationId values. They produce better operation page URLs than method-and-path fallback slugs.

Let the path fallback clean up unfinished specs, not define the long-term documentation structure.