DataTalksClub / DataTalksClub/website
Prevent nested links in documentation curriculum cards
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Parent accessibility baseline: #65
Product outcome
Curriculum cards render valid, unambiguous native-link semantics while preserving every source-authored destination. A linked curriculum item whose details contain another link becomes one visually unchanged neutral card with separate, clearly named link targets: the item title opens the item destination and each details link keeps its own destination. Items with only one destination retain the accepted whole-card interaction; items without a destination remain static.
This is a bounded accessibility and HTML-validity correction to the documentation presentation introduced by face8e4808d65afbf0374d1ced7a88079950d663. It does not alter curriculum data or redesign the documentation system.
Normative authority
_docs/PROCESS.md: role-separated implementation, full template/browser verification, and desktop/mobile screenshot inspection.- Specification 02 — URL, link, and SEO compatibility: docs paths, headings, embedded link destinations, canonicals, and source anchors remain exact.
- Specification 03 — GitHub content and people: source-backed documentation content and safe rendering remain authoritative.
- Specification 07 — Accessibility: semantic links, programmatic names, keyboard completion, visible focus, target sizing, reduced motion, and responsive reflow.
- Specification 10 — Verification strategy: synthetic browser evidence, responsive screenshot inspection, and release-critical link/accessibility regression coverage.
- #65's merged automated accessibility foundation is the reusable baseline. Its remaining HUMAN gate does not block this bounded regression fix and must not be claimed or closed by this issue.
Confirmed current regression
At current main/face8e4, content.docs_presentation.docs_curriculum() extracts the title destination from source-rendered Markdown, while templates/review/docs_detail.html wraps both the title and details_html in that destination anchor. Exactly two current projected items therefore contain an anchor in an anchor:
| Public page | Item-title destination | Details destination |
|---|---|---|
/docs/courses/data-engineering-zoomcamp/curriculum/ — Final Project |
https://github.com/DataTalksClub/data-engineering-zoomcamp/tree/main/projects |
/docs/courses/data-engineering-zoomcamp/project/ — Project page |
/docs/courses/llm-zoomcamp/curriculum/ — Capstone Project |
https://github.com/DataTalksClub/llm-zoomcamp/blob/main/project.md |
/docs/courses/llm-zoomcamp/project/ — Project page |
The source data and both destinations are correct. The presentation composition is the defect.
Scope and interaction contract
Structural classification
- Derive whether a curriculum item's already-sanitized rendered details contain one or more anchors as a presentation property. The rule is structural and generic: do not match course slug, item title, link label, or URL.
- When an item has a title destination and no details links, preserve the accepted whole-card native anchor, accessible name, pointer target, focus treatment, reduced-motion behavior, and destination.
- When an item has no title destination, preserve the accepted static card.
- When an item has both a title destination and one or more details links, render a neutral card container, not an anchor and not an element with
role="link"ortabindex. Render the visible item title as the native primary anchor to the title destination, and render the source-authored details HTML normally so its native anchors remain siblings/descendants of the neutral container rather than descendants of another anchor.
Names, destinations, and activation
- The primary anchors have concise names from the source item titles:
Final ProjectandCapstone Project. The local details anchors retain the visible nameProject page. No link's accessible name may absorb the other link's description or destination. - Keyboard order within each split card is primary title link first, followed by details links in source order. Each is reached once with
Tab, activated withEnter, and receives the shared visible, unobscured focus treatment. There is no duplicate tab stop, keyboard trap, scripted click forwarding, or card-level pseudo-link. - Pointer activation of the primary title link resolves to the exact external repository destination. Pointer activation of
Project pageresolves to the exact local documentation destination. Clicking non-link card background does nothing; no overlay or stretched-link hit area may cover or steal a details link. - Actual interactive targets retain the applicable shared target-size/spacing, contrast, forced-colors, and reduced-motion behavior. A neutral card must not present hover/focus animation that falsely promises whole-card activation.
Visual and content continuity
- Preserve the existing content-page shell, docs header/local navigation, curriculum ordering, marker, card border/background/radius/spacing, typography, responsive layout, light/dark themes, and all source-authored copy.
- Preserve all current item counts and ordering on every projected curriculum page. Preserve exact docs routes, headings/anchors, canonical metadata, source projection, source-authored URLs, sanitization, and fallback-to-complete-prose behavior.
- The split-link treatment must work for a generic future curriculum item with any title destination and one or more safe details anchors; it is not limited to the two current
Project pagecases.
Acceptance criteria
- Parsing the server response and inspecting the repaired browser DOM find zero nested anchors and zero interactive descendants inside a whole-card anchor on every current projected curriculum page.
- The Data Engineering
Final Projectcard exposes exactly one primaryFinal Projectlink tohttps://github.com/DataTalksClub/data-engineering-zoomcamp/tree/main/projectsand oneProject pagelink to/docs/courses/data-engineering-zoomcamp/project/; both are contained by one neutral visual card and neither contains the other. - The LLM
Capstone Projectcard exposes exactly one primaryCapstone Projectlink tohttps://github.com/DataTalksClub/llm-zoomcamp/blob/main/project.mdand oneProject pagelink to/docs/courses/llm-zoomcamp/project/; both are contained by one neutral visual card and neither contains the other. - A generic presentation unit test proves the split-card branch for a linked item with one or multiple details anchors without relying on course/title/link-label/URL text. It also proves the existing whole-card branch for a title-only destination and static branch for no title destination.
- Keyboard and pointer browser checks prove link order, unique tab stops, exact names/destinations, Enter activation, visible focus, non-link background behavior, and non-overlapping hit targets for both affected pages. The tests perform no live request to an external repository.
- Desktop
1440×900and mobile390×844renderings of both affected pages have no document-level horizontal overflow, lost/truncated content, covered link, or broken card geometry. The split controls remain usable at 200% zoom/320 CSS-pixel reflow, with reduced motion and forced colors. - The focused WCAG A/AA scan and explicit semantics checks pass for both affected pages. Existing docs hierarchy, source anchors, canonical/alias behavior, JavaScript-off read access, other curriculum cards, non-curriculum prose, and light/dark behavior do not regress.
- The independently recomputed versioned verification plan has no required skip. Focused Django/presentation tests, applicable docs/accessibility Playwright checks,
make test-playwright(template-change backstop), full Django/compatibility checks, lint/format/type/migration/portability/terminology checks, andgit diff --checkpass through uv-backed commands. - An independent tester captures and opens original screenshots below
.tmp/screenshots/issue-263/: both affected routes at desktop and mobile, plus representative visible keyboard focus on the primary andProject pagelinks and representative dark-theme evidence. Every image shows the expected page, correct destinations/controls, readable layout, and no error/debug/private data.
Required verification scenarios
- Render the current Data Engineering and LLM curriculum pages. Inspect server HTML and repaired DOM structure, accessible link names, exact hrefs, focus order, focus indication, pointer hit testing, local
Project pagenavigation, non-link card background, viewport overflow, reduced motion, forced colors, and axe results. - Render representative unaffected cases: a linked ML curriculum module with no details link remains one whole-card destination, an existing static curriculum item remains non-interactive, and a non-curriculum docs page remains ordinary prose.
- Exercise a synthetic generic item whose title has one destination and whose details contain multiple anchors. It splits into one neutral container and independent native links in source order, with no string/path special case and no dropped/sanitization-bypassing content.
- At desktop/mobile and 200%/320px, inspect both affected pages in the accepted shell and at least one dark-theme state. Verify card geometry/copy remains coherent and actual controls, not the neutral background, carry hover/focus affordance.
Non-goals
- No rewrite of curriculum facts, titles, descriptions, module ordering, source projection JSON, or source-authored URLs.
- No removal, redirection, relabelling, or replacement of either repository or local project-documentation destination.
- No redesign of documentation navigation, typography, page shells, card tokens, unrelated curriculum/prose pages, or global interaction primitives.
- No JavaScript card emulation, click forwarding, overlay/stretched anchor across sibling controls, ARIA role substitution for native anchors, or external network dependency in tests.
- No course-management, cohort, registration, learner, Studio, admin API, content-import, SEO-route, or deployment behavior change.
- No claim to complete #65's outstanding real screen-reader/HUMAN matrix or WCAG conformance.
Dependencies and sequencing
There is no product or architecture dependency. Start from then-current clean main. #261 owns the current P0 exact-main quality-gate recovery but supplies no interface required here and has no allowed-file overlap with this bounded fix; coordinate sequencing so #263's final verification is run on a green then-current base. If another docs/template change lands first, rebase and recompute the plan before tester handoff.
Delivery
Status after grooming: GROOMED / engineer-ready P1. Follow the full issue lifecycle: engineer implements and freezes an uncommitted candidate; an independent tester recomputes the plan, runs the selected gates, and inspects screenshots; PM accepts the exact candidate; only then may the engineer commit with Closes #263, followed by local no-ff merge/push and on-call observation. No pull request.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with content.docs_presentation.docs_curriculum() and templates/review/docs_detail.html, then read _docs/PROCESS.md and the linked accessibility and verification specifications. Add focused Django/presentation coverage for split, whole-card, and static cases, followed by Playwright checks on the two named curriculum routes. Done means no nested anchors, exact independent destinations and names, preserved unaffected cards, and passing responsive/accessibility verification.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, playwright, python
- Domain
- accessibility, documentation, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100