Skip to content

Docs: record the Bootstrap JS decision and guard it against Bootstrap 6 #33

Description

@fsecada01

Part of #34.

Summary

#29 ships the bootstrap theme as CSS only, with Alpine driving every interactive component and bootstrap.bundle.min.js deliberately absent. That is the right call, but it is currently an undocumented one: the reasoning exists only in a research artifact (claudedocs/research_bootstrap_js_convention_2026-07-29.md), which is a record of what was investigated, not a record of what was decided.

Two concrete gaps follow from that, and this ticket closes both.

Consumers have no guidance. Bootstrap ships 13 JS-driven components. cf-ui wraps 5 of them. A consumer who wants a toast, an offcanvas, a carousel, or scrollspy has no documented answer for whether they may add Bootstrap's bundle themselves, and no warning about what happens if they do.

The decision has no expiry mechanism. It was made against Bootstrap 5 and is correct for Bootstrap 5. Bootstrap 6 changes the premises, and nothing in the repo will notice.

Why this needs a tripwire rather than a note

Verified directly against v6-dev (secondary sources on this are unreliable — several claim v6 already moved to native <dialog> citing twbs#41751, which is closed and was never merged; twbs#39191 is closed NOT_PLANNED):

  • modal.js and _modal.scss are gone. They are replaced by dialog.ts / dialog-base.ts / _dialog.scss, built on HTMLDialogElement.showModal().
  • _dialog.scss on v6-dev defines .dialog, .dialog-header, .dialog-body, .dialog-footer, .dialog-title, .dialog-scrollable, .dialog-fullscreen, .dialog-static, .dialog-nonmodal, .dialog-instant, .dialog-slide-up, .dialog-slide-down, .dialog-swap-in, .dialog-open. Not one .modal* selector.
  • cf-ui's bootstrap modal templates carry 8 modal-* class references each (jinja/bootstrap/Modal.jinja, cotton/_themes/bootstrap/modal.html).
  • v6 is expanding its JS surface, not shrinking it — combobox, datepicker, otp-input, chips, strength, drawer, menu, range are all new JS components on the branch.

So the bootstrap theme's markup breaks at v6 regardless of the JS decision, which is the useful part: the JS question gets re-asked for free the day the v6 markup rework happens. There is no need to pre-solve it now, and no need to rely on anyone remembering — the version bump is the natural trigger, and it is already a single pinned value in this repo.

The pin is the hook

# src/cf_ui/templatetags/cf_ui.py
_DEFAULTS = {
    "bootstrap": "5.3.3",
    ...
}

Nothing in tests/ reads _DEFAULTS today. Guard it: a test that fails the moment this leaves the 5.x line, whose failure message is the checklist of what to reconsider. This is the pattern #17 established — pin the thing, and let the break on bump be the signal, rather than trusting a promise to monitor.

Whoever bumps that version is then forced to read the decision at the exact moment revisiting it is cheapest.

Acceptance criteria

  • Failing test first: a unit test asserting _DEFAULTS["bootstrap"] is on the 5. major line, with a failure message that names what to re-evaluate on v6 — .modal-*.dialog-* class renames, showModal() vs. the role="dialog" decision recorded in Epic: axis + component hardening — close deferred review findings from #5, #6, #7 #19, whether v6's larger JS surface changes the CSS-only stance, and whether a driver/facade abstraction is warranted by then.
  • docs/bootstrap.md, following the shape of docs/daisyui.md, recording:
    • The decision, plainly: CSS only, Alpine drives behaviour, bootstrap.bundle.min.js is not emitted by cf_ui_body.
    • Why — Bootstrap sanctions framework-native replacement of its JS; a single behavioural contract (Alpine.store('cf').modal.open(id)) has to hold identically across all themes; Bootstrap ships no no-JS fallback at all, while cf-ui's js_off E2E tier is a stated guarantee.
    • Which of Bootstrap's 13 JS components cf-ui covers, and which it does not.
    • What a consumer should do to use an uncovered Bootstrap component, and the explicit warning that adding the bundle makes Bootstrap's JS a second state owner for the 5 components cf-ui already drives — data-bs-* attributes must not be added to cf-ui components.
    • The Bootstrap 6 note, stating what changes and that the pin test is the trigger.
  • The driver/facade option is recorded as a considered-and-deferred alternative, with the reason (an abstraction for a problem no consumer has reported, designed against an API that does not exist yet) — so it is not relitigated from scratch.
  • README's theme table or theme docs index links docs/bootstrap.md.

Delivery

Scoped to #29's branch — it is that PR's missing documentation, and splitting it into a follow-up would ship an undocumented decision in the meantime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions