Accessibility

Accessibility is built into the components (native <details> / <dialog>, ARIA on the navbar toggle, keyboard tables on each interactive page). This page covers the framework-wide helpers.

Screen-reader text

.screen-reader-text hides an element visually but keeps it in the accessibility tree — for extra context on a link, a <caption>, a form-control group label.

Find out more about jellyfish species — visually identical to a plain link; inspect it or turn on a screen reader to find the extra text.

Focus outlines

Buttons, links and form controls get a clear :focus-visible outline for keyboard users; it's suppressed for pointer users (form fields keep theirs, per spec). Tab through these:

A plain link
Link button

The outline is --jf-accessibility-focus-color — override it at :root or a scope.

Contrast linter

Every colour pair Jellyfish generates is scored against the WCAG 2.x contrast ratio at build time — each palette shade against its --jf-color-on-* text colour, plus buttons, chips, callouts, tables, .bg-* surfaces, <mark>, and the dark-mode text-on-canvas pairs. Anything below the threshold prints a Sass @warn naming the pair and its score. Treat a warning as a failing test — it means a colour you added can't be read on the surface it's paired with.


    WCAG: palette on-colour contrast has pairs below 4.5:1:
      on-brand-400: #ffffff on #7fb8a4 scores 2.31:1
  

Run it over your own pairs with the same mixin the framework uses — pass a list of (label text background) triples and a context name:


    .promo {
      color: get-color-raw(primary, 900);
      background: get-color-raw(primary, 100);
      @include contrast-lint(
        ("promo text" get-color-raw(primary, 900) get-color-raw(primary, 100)),
        "promo"
      );
    }
  

Both arguments must be literal colours, so use get-color-raw() rather than get-color() — a var() reference can't be scored at build time. Settings: $contrast-lint (off switch), $contrast-lint-warn (score silently), $contrast-lint-threshold (default 4.5; 3 for the AA large-text exception).

The linter only sees pairs it's handed. Anything where you set a colour without telling it what's behind — a .text-{family} utility, a hand-written rule — is yours to check.

Reduced motion & forced colours

  • prefers-reduced-motion: reduce zeroes every framework transition (the indeterminate progress bar slows instead of stopping).
  • In Windows High Contrast mode the masked chevron, progress bar and modal buttons repaint from system colours so they stay visible.

Font-size control

Give any button data-font-size="smaller|default|larger|largest". The bundled accessibility.js adds the matching .font-size-* class to <html> (a multiplier on --jf-root-font-size, so the whole rem scale grows), stores the choice in localStorage["jf-font-size"], and sets aria-pressed on the active button. Handled by delegation (CSP-safe); window.setRootFontSize('larger') is exposed for scripts.


    
    -->
Adjust text size: