Card
A bounded region of content, with an optional real heading and a footer.
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><x-wsu::card title="Request an override" :level="2">
<p>Ask the department to let you into a closed section.</p>
<x-slot:footer>
<x-wsu::button variant="primary" type="submit">Submit request</x-wsu::button>
<x-wsu::button variant="ghost">Cancel</x-wsu::button>
</x-slot:footer>
</x-wsu::card><Card title="Request an override" :title-level="2">
<p>Ask the department to let you into a closed section.</p>
<template #footer>
<Button variant="primary" type="submit">Submit request</Button>
<Button variant="ghost">Cancel</Button>
</template>
</Card>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
| Attribute | Default | What it does |
|---|---|---|
title | null | Rendered as a heading. |
level | 2 | Heading level, 1 through 6. |
titleId | slug of the title | Used by aria-labelledby. |
Vue
| Prop | Type and default | What it does |
|---|---|---|
title | String, '' | Or use the title slot. |
titleLevel | Number, 2 | Validated to 1 through 6. |
titleId | generated | Overrides 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.
| Template | Elements | Accessibility attributes | Uses |
|---|---|---|---|
| internal apps/examples/static-html/index.html | div | none recorded | 1 |