Phone
A phone body around whatever the slot holds.
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-phone" role="group" aria-label="Phone preview">
<span class="wsu-phone__notch" aria-hidden="true"></span>
<div class="wsu-phone__screen">
<p class="wsu-prose" style="padding:var(--wsu-space-4)">Next class: CSC 2110 at 10:30</p>
</div>
</div><x-wsu::phone>
<p class="wsu-prose" style="padding:var(--wsu-space-4)">Next class: CSC 2110 at 10:30</p>
</x-wsu::phone>
<x-wsu::phone label="Phone preview, brand case" variant="brand">
<p class="wsu-prose" style="padding:var(--wsu-space-4)">Next class: CSC 2110 at 10:30</p>
</x-wsu::phone><Phone>
<p class="wsu-prose" style="padding: var(--wsu-space-4)">Next class: CSC 2110 at 10:30</p>
</Phone>
<Phone label="Phone preview, brand case" variant="brand">
<p class="wsu-prose" style="padding: var(--wsu-space-4)">Next class: CSC 2110 at 10:30</p>
</Phone>Why it works this way
- Browser and Window are decoration: hiding their chrome loses nothing, because a screenshot or a filename already says what it needs to say on its own. A phone body is different. Its shape is what tells a sighted reader "this is what it looks like on a phone", a fact nothing else on the page states, so aria-hiding the frame the way the other two are hidden would remove that fact for anyone not looking at it.
- So this carries role="group" and a label instead of aria-hidden. The notch is the one piece with nothing of its own to say, and stays aria-hidden.
- A wallpaper is already just an <img> in wsu-phone__screen, sized to the slot the same way a full-bleed Browser screenshot is: nothing to add, and nothing this page builds twice.
- `variant` recolors the case, and the notch along with it so the notch still reads as a cutout in the case rather than a second color sitting on top of it. The bezel, the ring of hardware around the case, stays neutral regardless: a real case's rim does not usually match its shell either. Neither the case nor the notch carries text, so there is no foreground to prove contrast for here the way wsu-terminal below has to.
Accessibility
- The frame is a labeled group rather than hidden, so the "on a phone" context a sighted reader gets from the shape has a spoken equivalent (1.1.1).
- The label is a prop rather than fixed text, so two phones on one page can be told apart instead of both announcing themselves identically.
- The slot content stays a plain, reachable child of the group. Nothing about labeling the frame removes or wraps what is inside it.
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 |
|---|---|---|
label | 'Phone preview' | What a screen reader hears in place of the shape a sighted reader sees. |
variant | '' | '' | 'brand' | 'accent' | 'success' | 'danger'. Recolors the case and the notch. |
Vue
| Prop | Type and default | What it does |
|---|---|---|
label | String, 'Phone preview' | What a screen reader hears in place of the shape a sighted reader sees. |
variant | String, '' | '' | 'brand' | 'accent' | 'success' | 'danger'. Recolors the case and the notch. |
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-phone.
| Template | Elements | Accessibility attributes | Uses |
|---|---|---|---|
| internal apps/examples/static-html/index.html | div | aria-labelrole | 1 |
| public apps/examples/static-html/public-app.html | div | aria-labelrole | 1 |