Skip to content

🧭 Roadmap: backlog triage, modernization, card syntax redesign & new components #265

Description

@chrisjsewell

Context

This is a tracking issue consolidating a full triage of the open backlog (56 issues, 14 PRs as of 2026-07), a code-level review of the extension, and a forward plan β€” to agree direction before implementation starts.

Groundwork already landed: v0.7.0 (Python 3.11–3.14, Sphinx 7–9) via #250/#255/#256, AGENTS.md (#251, #254), Sass @importβ†’@use migration (#259), tab-set crash fix (#258).

Implementation briefs: each work item below has a detailed, self-contained brief (one PR each, with file:line references, steps, tests, and acceptance criteria) on the claude/sphinx-design-modernize-orr9g0 branch under briefs/, including an execution plan with parallelization tracks and a file-conflict matrix.


1. Open PR triage

PR Verdict Notes
#205 βœ… merged via #266 (81dbab8) Verified: OCTICON_CSS in icons.py was dead code. Original fork branch couldn't re-trigger required checks (2024 runs too old to re-run), so re-created with authorship preserved
#262 βœ… merged (03ccc10) pre-commit autoupdate (ruff 0.15, mypy 2.1); [dependency-groups] pins synced in #267
#264 βœ… merged via #270 (834eebe) Button i18n fix, carried with authorship credit + crash hardening and i18n test coverage. Closed #96, #44, #263
#230 πŸ”¨ being carried Focus rings (a11y) β€” being ported onto the post-@use SCSS with author credit, as part of the a11y pass (brief 10, in progress)
#158 πŸ” review & land Button docs clarification; needs rebase
#241 βœ… closed Superseded by the merged #276 (static-asset rework), which includes its HTML-only gating; credited in-thread
#237 βœ… closed .readthedocs.yml on main already has sphinx.configuration
#220 βœ… closed pyproject already allows myst-parser>=4,<6
#203 βœ… closed Superseded by the merged #272 (codecov-action v5 + fixing the dead upload condition)
#175 βœ… closed Superseded by #264/#270
#221 #225 #226 #227 βœ… closed Superseded by the merged #267 (pins refreshed + dependabot groups)

2. Open issue triage (by cluster)

i18n β€” βœ… buttons fixed

#44, #96, #263 closed by #270. Remaining: #234 (table content inside tabs missing from .pot) β€” separate extraction bug to investigate. Known gap documented in #270: button-ref text is absent from .pot extraction (std-domain xref resolution flattens explicit-title content before the gettext builder extracts); translation itself works.

Static files / builder lifecycle β€” βœ… fixed

#200, #235 closed by #276: static assets are now served via Sphinx's standard html_static_path mechanism (HTML-format builders only), nothing is written into outdir outside Sphinx's own copying, and the Sphinx floor moved to β‰₯7.2.

LaTeX output

#107 (dropdown β†’ \subsubsection*), #218 (same for tabs), #179 (grids with images), #242 (fontawesome5 package clash β€” fix in progress via the FontAwesome modernization). The extension has essentially no LaTeX visitors; everything degrades via sphinxuseclass. Plan: a dedicated LaTeX pass β€” dropdown/tab-item β†’ boxed environments (e.g. sphinxShadowBox-style), grids β†’ sequential blocks, and conditional fontawesome5 loading.

Tabs

Cards / grids

Icons

Refs / links

Docs-only quick wins β€” βœ… done

#172, #122, #184, #247 closed by #273. Remaining: #52 (indent MyST examples).

Close / answer β€” βœ… done

#6, #77, #80, #177, #165, #182 all closed with explanations; #260 βœ… done in #277 (public sphinx_design.testing module).

3. Modernization plan

  1. Rework static-asset handling βœ… done in ♻️ Serve static assets via html_static_pathΒ #276 β€” update_css_js/update_css_links replaced by a single builder-inited hook registering sphinx_design/static/ on html_static_path + add_css_file/add_js_file (HTML-format builders only, served filenames unchanged); Sphinx floor bumped to β‰₯7.2 (native ?v= checksums), md5 branch and test-suite compat shims deleted.
  2. CI coverage is silently dead βœ… fixed in πŸ§ͺ Fix dead codecov upload, modernize CI actionsΒ #272 (condition, codecov-action v5, action bumps, concurrency group). Follow-up idea from Phase 1 friction: run the no-myst tox env in CI and widen tox -e mypy to cover tests/, so all checker environments agree (several Phase 1 failures were only visible in envs CI doesn't run). Phase 2 addendum: the ~=7.0 CI rail resolves to 7.4.x, so the declared 7.2 floor is never CI-tested β€” three floor-only bugs were caught in local pinned-version runs; consider adding a sphinx==7.2.* matrix entry.
  3. PyPI Trusted Publishing (OIDC) β€” replace the long-lived PYPI_KEY secret + flit publish with pypa/gh-action-pypi-publish under a pypi environment; attestations for free. Deferred for now β€” needs a one-time publisher registration on PyPI; revisit before the next release.
  4. Drop the _compat.findall shim βœ… done in ♻️ Serve static assets via html_static_pathΒ #276 β€” all call sites now use node.findall(...) directly (note for downstream: the private helper is gone).
  5. Packaging polish: bump Development Status :: 4 - Beta β†’ 5 - Production/Stable; adopt PEP 639 license = "MIT"; refresh theme extras pins (done in ⬆️ Refresh dev/docs pins, group dependabot updatesΒ #267); plan a 1.0 once i18n + static-asset fixes land.
  6. Frontend hygiene: bump the sass pin (package.json/pre-commit still pin 1.35.2 from 2021); a11y pass (in progress: Restore focus ringsΒ #230 + Include radio/label ID as part of tab-content divΒ #30); FA import opt-out (in progress: FontAwesome import interfering with Pro LicenseΒ #174).
  7. LaTeX degradation pass (see cluster above) β€” largest coherent pain cluster after i18n.
  8. Testing gaps: no i18n/gettext tests (βœ… added in πŸ› Keep buttons intact under gettext translationΒ #270); JS behaviour (tab sync) still entirely untested β€” doctree regressions can't catch Click+drag on tab causes synced tabs to go out of syncΒ #46/Tab-item is modifying .html filesΒ #238-class bugs, and the πŸ› Ignore comments/targets in component child validationΒ #271 anchor bugs (fixed in πŸ› Keep target anchors rendered in tab-set and tab-set-codeΒ #275) were likewise invisible to doctree assertions. Add a minimal Playwright smoke test.
  9. Declarative configuration βœ… landed in ♻️ Central declarative SdConfig dataclassΒ #274: all sd_* options on a typed dataclass (modelled on myst-parser's MdParserConfig + validators), every field TOML-representable. New options (tabs storage prefix, FontAwesome source/LaTeX) are being added as fields.

4. Card directive: replace bespoke header/footer syntax with a pure parse

Today card (and grid-item-card via CardDirective.create_card) pre-processes its raw source lines: split_content regex-scans for the first ^{3,} line (header separator) and the last \+{3,} line (footer separator), slices the StringList into three chunks, and nested-parses each separately.

Problems with this:

  • False positives in nested content β€” a +++ or ^^^ line inside a nested code-block/literal block (e.g. Jupytext cell markers, rST section underlines in examples) is treated as a separator. The "last occurrence" heuristic for footers mitigates but doesn't solve.
  • Approximate source mapping β€” there's a literal TODO set proper lines in _create_component; error locations inside cards are off.
  • Invisible to tooling β€” the separators aren't part of any parse; formatters, MyST linters/LSPs, and other renderers (including any future non-Python MyST implementation) can't understand card structure.
  • add_card_child_classes then stamps sd-card-text onto all descendant paragraphs (βœ… fixed in πŸ› Stamp sd-card-text on direct paragraphs only, never replace classesΒ #278 β€” now direct children only).

Proposal: card-header / card-footer sub-directives + doctree hoisting

Adopt the same structural pattern as tab-set/tab-item:

  • Register card-header and card-footer directives. Content of card is parsed with one ordinary nested_parse (pure rST/MyST β€” no raw-text surgery).
  • After parsing, the card directive hoists any card-header/card-footer component children into their slots and wraps the remaining siblings in card-body. Pure doctree manipulation, correct line attribution for free.
  • card-header/card-footer used outside a card warn, mirroring tab-item.
.. card:: Card title

   .. card-header::

      Header content

   Body content

   .. card-footer::

      Footer content

Ergonomics notes:

  • Slightly more verbose than ^^^/+++, but explicit, unambiguous, and identical in rST and MyST (MyST users already nest fences for tab-set/tab-item).
  • Optionally also add :header:/:footer: options accepting inline markup for the very common one-liner case β€” to decide.

Alternative considered (rejected): transition-based splitting

Parse the content and split on nodes.transition (the old sphinx-panels approach). Rejected because the two parsers disagree: ^^^^ (4+) parses as a transition in rST but +++ does not, while MyST tokenizes +++ as a block-break β€” so no single separator has consistent semantics across parsers, and transitions inside genuine card body content would be misinterpreted.

Deprecation pathway (not back-breaking)

  1. vNext (0.8): both syntaxes work; docs/examples switch to the new sub-directives; ^^^/+++ remain the default-on legacy path.
  2. Add config sd_card_legacy_separators (default True) and emit a once-per-document deprecation notice (subtype design.card_legacy, suppressible) when separators are used.
  3. Publish a short migration guide (precedent: the sphinx-panels migration docs); the rewrite is mechanical enough for a python -m sphinx_design.migrate helper if wanted.
  4. 1.0/2.0: flip the default off; remove one major later.

5. New components & directive improvements

New directives that fit the repo's CSS-first / minimal-JS philosophy:

  • accordion β€” a group of dropdowns where opening one closes the others. Dropdowns already render as <details>/<summary>, and native HTML <details name="..."> gives exclusive-open behaviour with zero JS (Baseline 2024). Implementation is essentially a container directive assigning a shared name + CSS. Bootstrap-parity component that gets asked for regularly.
  • steps / step β€” numbered procedure steps (install guides, tutorials), CSS counters only. One of the most-copied custom CSS snippets across Sphinx sites.
  • aside (Aside boxesΒ #97) β€” floated call-out box with text wrap-around; CSS-only, long-standing request.
  • tooltip β€” either a role or a :tooltip: option on badges/buttons (Add tooltip for badgesΒ #81) in progress: ; tooltip suffix syntax on badge roles.

Improvements to existing components (no new directives): vertical tab orientation (#219), carousel controls via CSS scroll-snap (#181, #133), card img-left/right (#211), dropdown FA icon option (#233).

Considered and decided out of scope: menu-style dropdowns / nav widgets (#165, closed) β€” interactive navigation rather than content components; better served by themes.

6. Suggested sequencing

Feedback welcome on any of the verdicts above β€” in particular Β§4 (card syntax) and which of Β§5 to green-light.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions