Skip to content

fix(portal): W3C HTML validation fixes on public portals#65

Merged
BatLeDev merged 7 commits into
masterfrom
fix-w3c-validation
May 27, 2026
Merged

fix(portal): W3C HTML validation fixes on public portals#65
BatLeDev merged 7 commits into
masterfrom
fix-w3c-validation

Conversation

@BatLeDev
Copy link
Copy Markdown
Member

@BatLeDev BatLeDev commented May 27, 2026

  • Clean up W3C HTML validation errors on public portals: stop emitting <a href aria-disabled> on the current breadcrumb (last item is stripped of to/href so Vuetify renders it as plain text inside the <li>), move role="status" off heading elements onto wrapper <div>s in catalog-layout, replace <v-divider>/<div> inside title headings with phrasing <span>s + aria-hidden, drop the redundant role="navigation" on <nav> in skip-links, and stop emitting target on non-<a> tags via a local patch on Vuetify's useLink composable.
  • Bump vuetify ^4.0.3^4.0.7 and rebase the local patch on the new version. New patch hunk on theme.js: drop the upstream tagPosition: 'bodyOpen' workaround so the theme stylesheet stays in <head> (HTML-valid), and prepend the canonical @layer vuetify-core, vuetify-components, vuetify-overrides, vuetify-utilities, vuetify-final; declaration to preserve the cascade regardless of parse order vs. main.css. New patches/README.md documents both hunks and their removal criteria.
  • Stop passing cspNonce to Vuetify in plugins/03-vuetify.ts: nuxt-security already adds a nonce to every <style> during SSR, the extra cspNonce produced a duplicate nonce= attribute on the theme stylesheet.
  • Add explicit bgOpacity / bufferOpacity defaults on VProgressLinear in nuxt.config.ts to work around vuetifyjs/vuetify#22876 — without them SSR emits style="opacity:NaN". Values match the CSS fallback (var(--v-border-opacity) = 0.12).
  • Rework d-frame-wrapper: the old .client.vue variant was replaced at SSR by a ServerPlaceholder <div> that received unknown custom-element attrs (src, aspect-ratio, iframe-title…) and was rejected by the W3C validator. The new wrapper uses <ClientOnly> with inheritAttrs: false, so no caller attrs reach the SSR placeholder. <d-frame> itself is pre-registered by plugins/dframe.client.ts (statically importing @data-fair/frame/lib/d-frame.js) so customElements.define always runs before any <d-frame> is created — otherwise Vue would set the .adapter IDL property on a not-yet-upgraded element and the constructor would overwrite it.
  • Bump Node engines v24>=24.11.0 (.nvmrc aligned on 24.11.1) and pass --error-on-fail to npx patch-package in the Dockerfile so a future vuetify bump that breaks patch application fails the Docker build with a clear signal instead of silently skipping the patch.

BatLeDev added 4 commits May 26, 2026 14:53
- layout-title: keep only phrasing content inside h1..h6 (decorative <span>
  stand-ins instead of <v-divider>/<div>); accessibility-improving since
  the decorative lines no longer carry an erroneous role="separator"
- d-frame-wrapper: switch from .client.vue to <ClientOnly> + inheritAttrs:false
  so SSR no longer leaks <div iframe-title="..." src="..." aspect-ratio>;
  .client.vue alone could not strip the attrs because Nuxt swaps the
  component for its internal ServerPlaceholder (whose inheritAttrs:true
  default is what's actually applied in SSR)
- nuxt.config: set VProgressLinear bgOpacity/bufferOpacity defaults to bypass
  parseFloat(undefined) === NaN ending up in SSR-emitted style="opacity:NaN"
  (workaround for vuetifyjs/vuetify#22876)
- catalog-layout: move role="status" / aria-live live region off the
  heading and off v-col onto a wrapping <div>; role="status" is invalid
  on heading elements per W3C, and the vuetify/grid-unknown-attributes
  lint rule rejects non-grid attrs on v-col
- layout-skip-links: drop redundant role="navigation" on <nav>
- portal/app/plugins/03-vuetify.ts: stop passing cspNonce to Vuetify;
  nuxt-security already adds a nonce on every <style> during SSR, so the
  extra cspNonce produced a duplicate `nonce=` attribute on the theme
  stylesheet (W3C duplicate-attribute error)
- patches/vuetify+4.0.7.patch (theme.js): drop tagPosition: 'bodyOpen'
  and prepend the canonical @layer order to the theme stylesheet content;
  keeps the cascade correct while putting <style> back inside <head>
  (HTML-valid)
- patches/vuetify+4.0.7.patch (router.js): resync of the existing
  iframe-href patch from the previous 4.0.3 file (no functional change)
- patches/README.md: document the vuetify patches with upstream links
  and removal criteria
- portal/package.json: pin vuetify to ^4.0.7 so the patch matches the
  installed version
- .nvmrc + package.json engines: bump Node requirement to >=24.11.0 to
  match what current postcss/cssnano transitive deps need

Refs: vuetifyjs/vuetify#22656
…rent breadcrumb

Vuetify's useLink patch was forwarding `target="_top"` to every element rendered by
v-btn (including <button>), and v-breadcrumbs-item exposed the current page as an
<a href aria-disabled="true"> — both invalid HTML flagged by W3C.

- patch useLink so `target` is only added when the element is actually a link (<a>).
- strip `to`/`href` from the last breadcrumb item so it renders as plain text inside
  the <li>; the existing CSS only styles `.v-breadcrumbs-item--link`, so visuals stay
  identical and `aria-current="page"` keeps conveying the semantic state.
@github-actions github-actions Bot added the fix label May 27, 2026
@BatLeDev BatLeDev force-pushed the fix-w3c-validation branch from f3a08d6 to bef62e0 Compare May 27, 2026 07:28
The previous lockfile had dangling references to transitive deps
(@emnapi/core, @emnapi/runtime, sass@1.99.0, chokidar@4.0.3,
readdirp@4.1.2) without top-level entries, causing `npm ci` to fail.
Regenerated cleanly from package.json — no version drift on resolved
packages.
@github-actions github-actions Bot added fix and removed fix labels May 27, 2026
The previous lockfile was generated incrementally and missed top-level
entries for transitive deps required by some optional sass-embedded
variants. `npm ci` validates the full graph and was failing with
'Missing: sass@1.99.0' etc. Regenerated from a clean install which
resolved all platform variants and their transitive deps.
@BatLeDev BatLeDev merged commit ff068d1 into master May 27, 2026
3 checks passed
@BatLeDev BatLeDev deleted the fix-w3c-validation branch May 27, 2026 09:10
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