Skip to content

Card

A bounded region of content, with an optional real heading and a footer.

Preview

Code

The three render the same class names, the same ARIA and the same data attributes. That is checked when this site builds: a class in any of these samples that neither the markup contract nor the shipped stylesheet defines fails the build.

<div class="wsu-card">
  <!-- A real landmark inside the card, here a form, names itself after the
       heading. aria-labelledby on the card's own outer div would do nothing:
       a plain div has no implicit role for ARIA to attach a name to. -->
  <form aria-labelledby="override-title">
    <h2 class="wsu-card__title" id="override-title">Request an override</h2>

    <p>Ask the department to let you into a closed section.</p>

    <div class="wsu-card__footer">
      <button class="wsu-btn wsu-btn--primary" type="submit">Submit request</button>
      <button class="wsu-btn wsu-btn--ghost" type="button">Cancel</button>
    </div>
  </form>
</div>

Why it works this way

  • The title renders as a heading element rather than a styled paragraph, so the card contributes to the document outline and a screen reader user can move between cards with heading navigation.
  • level exists because a card's correct heading level depends on where the page puts it. Guessing h2 every time produces outlines that skip levels.

Accessibility

  • A real heading, not a styled p (1.3.1).
  • The card itself carries no aria-labelledby: a plain div has no implicit role, and ARIA ignores a labelling attribute on one, so it would name nothing (confirmed against a real accessibility tree). The heading carries a stable id instead, for a real landmark inside the card (a form, most often) to point at with its own aria-labelledby.

Success criteria in brackets refer to WCAG 2.2. Every one of them is checked by axe-core in both themes at three viewport widths before this page can be published. See Accessibility for what the gates are.

Props

Blade

AttributeDefaultWhat it does
titlenullRendered as a heading.
level2Heading level, 1 through 6.
titleIdslug of the titleUsed by aria-labelledby.

Vue

PropType and defaultWhat it does
titleString, ''Or use the title slot.
titleLevelNumber, 2Validated to 1 through 6.
titleIdgeneratedOverrides the generated heading id a landmark inside the card can point at.

In the markup contract

contract/markup-contract.json is extracted from the two static templates and every package tests against it. This is what it records for .wsu-card.

TemplateElementsAccessibility attributesUses
internal apps/examples/static-html/index.htmldivnone recorded1