Skip to content

fix(shortcodes): migrate .Ordinal ids to the UniqueID helper#2026

Merged
markdumay merged 8 commits into
mainfrom
feat/ordinal-id-migration
Jul 15, 2026
Merged

fix(shortcodes): migrate .Ordinal ids to the UniqueID helper#2026
markdumay merged 8 commits into
mainfrom
feat/ordinal-id-migration

Conversation

@markdumay

@markdumay markdumay commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Shortcodes built their DOM id from Hugo's .Ordinal, which resets to 0 inside the example shortcode's embedded RenderString. So two of a component in two {{< example >}} blocks both became accordion-0, and Bootstrap's querySelector-based data-bs-parent drove the wrong element — the second accordion's toggle opened the first's panel. This hit the component-documentation pages hardest, where every component is wrapped in {{< example >}}.

Every .Ordinal-derived id now uses mod-utils' UniqueID helper (<prefix>-UID-<n>, from a per-page Store counter).

Two mechanisms

  • Self-contained (carousel, navbar, toast, file, docs): a direct swap of the default-id expression, preserving the explicit-id override.
  • Parent/child coupled (accordion↔accordion-item, nav↔nav-item): the child used to rebuild its parent's id from .Parent.Ordinal. A counter can't be recomputed by the child, and Hugo renders children before the parent body — so the parent can't push its id down. The fix is a lazy shared id: whichever renders first mints the id and stores it in the parent's .Scratch; the parent and its other items read it back. The explicit id still wins, and the child keeps its own .Ordinal as the parent-scoped item index for the -item-<n> / -btn-<n> suffix.

img is untouched — its .Ordinal is a parent-scoped active-slide test, not an id.

Also here

A pre-existing carousel bug the migration surfaced: the indicators targeted #carousel-{{ $id }} (a doubled prefix → a non-existent id) while prev/next used #{{ $id }}, so indicator clicks were dead on multi-slide carousels. Corrected to #{{ $id }}, and the fixture strengthened to two-slide carousels that browser-verify each carousel's indicators advance only its own.

Note on generated ids

Every auto-generated id changes shape (accordion-0 becomes accordion-UID-1). These ids are auto-generated and undocumented, and every affected shortcode still honours an explicit id argument — the escape hatch for a stable anchor. This is an implementation-detail change, cut as a fix: patch; the caveat belongs in the release note. (Deliberately not flagged as a semver-major change — the ids are not a public contract.)

Verification

exampleSite/content/en/id-demo.md is a permanent regression fixture: each component twice, inside separate {{< example >}} blocks (escaped-nesting idiom, so they render live through the example shortcode's RenderString — exactly the collision path). Whole-site scan confirms no bare <prefix>-<n> id remains and the fixture's components get distinct -UID- ids. In a browser: the second accordion's item opens only its own panel (the core regression), the second nav's tab switches only its own pane, carousels advance independently, and the explicit-id override flows through parent and child — zero uncaught console exceptions.

Companion PRs (independent — mod-utils v6.5.0 already released)

Each carries a fix: commit; merge in any order. Hinode's exampleSite renders bare -N lottie/leaflet ids until those two modules release and exampleSite/go.mod is bumped — a known post-merge follow-up.

🤖 Generated with Claude Code

markdumay and others added 7 commits July 15, 2026 06:48
Twelve shortcodes build a DOM id from .Ordinal, which resets to 0 inside the
example shortcode's embedded RenderString, so two accordions in two example
blocks collide on accordion-0. Migrate the 11 real id sites to UniqueID:
self-contained shortcodes swap directly; accordion/nav parent-child share the
id lazily through the parent's Scratch, since Hugo renders children before the
parent body. img is excluded (its ordinal is a parent-scoped slide index).

Folds in an unrelated preview.html fix: a dangling aria-labelledby in the
fallback path, where panes reference tab controls the fallback never renders.
Seven tasks across hinode, mod-lottie, mod-leaflet and mod-blocks. Each branch
is independent (mod-utils v6.5.0 already released); merge in any order.
carousel, navbar, toast, file and docs built their id from .Ordinal, which
resets to 0 inside the example shortcode's embedded RenderString - so two of a
component in two example blocks collided. Use the UniqueID helper, which counts
from a page Store counter. The explicit id argument still overrides.
The item rebuilt its parent's id from .Parent.Ordinal, which collides inside the
example shortcode. A UniqueID counter cannot be recomputed by the child, and
Hugo renders children before the parent body so the parent cannot push its id
down. Instead the first renderer mints the id and stores it in the parent's
Scratch; the parent and its other items read it back. The explicit id argument
still wins.
nav-item rebuilt its parent's id from .Parent.Ordinal, which collides inside the
example shortcode. Resolve it the same way as the accordion: the first renderer
mints a UniqueID and stores it in the parent's Scratch; the nav container and its
items read it back. The explicit id argument still wins.
The carousel indicator buttons targeted #carousel-{id}, doubling the
"carousel" prefix already present in $id (e.g. #carousel-carousel-UID-1).
This id never existed, so clicking an indicator did nothing on any
multi-slide carousel. The prev/next controls already targeted #{id}
correctly; align the indicators to match.

Give the id-demo fixture carousels two slides each so indicators
actually render and the fix is verified end to end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy Preview for gethinode-demo ready!

Name Link
🔨 Latest commit 113420f
🔍 Latest deploy log https://app.netlify.com/projects/gethinode-demo/deploys/6a5768f9749e780008dfa1da
😎 Deploy Preview https://deploy-preview-2026--gethinode-demo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@markdumay markdumay merged commit 5728678 into main Jul 15, 2026
16 checks passed
@markdumay

Copy link
Copy Markdown
Collaborator Author

🎉 This PR is included in version 3.2.3 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant