Chat
A conversation, read in the order it happened.
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.
<ol class="wsu-chat" aria-live="polite" aria-label="Conversation with your advisor">
<li class="wsu-chat__message">
<span class="wsu-chat__avatar">
<span class="wsu-avatar wsu-avatar--sm" role="img" aria-label="Pat Nguyen">PN</span>
</span>
<div class="wsu-chat__content">
<div class="wsu-chat__header">
<span class="wsu-chat__name">Pat Nguyen</span>
<time class="wsu-chat__time" datetime="2026-11-02T09:14">9:14 AM</time>
</div>
<p class="wsu-chat__bubble">Your advising hold clears once you're under 12 credits or I approve the overload.</p>
</div>
</li>
<li class="wsu-chat__message wsu-chat__message--sent">
<span class="wsu-chat__avatar">
<span class="wsu-avatar wsu-avatar--sm" role="img" aria-label="You">EE</span>
</span>
<div class="wsu-chat__content">
<div class="wsu-chat__header">
<span class="wsu-chat__name">You</span>
<time class="wsu-chat__time" datetime="2026-11-02T09:20">9:20 AM</time>
</div>
<p class="wsu-chat__bubble">Please approve the overload, I need CSC 2110 this term.</p>
<span class="wsu-chat__status">Delivered</span>
</div>
</li>
</ol><x-wsu::chat label="Conversation with your advisor" :items="[
[
'from' => 'received', 'name' => 'Pat Nguyen', 'time' => '9:14 AM', 'datetime' => '2026-11-02T09:14',
'message' => 'Your advising hold clears once you are under 12 credits or I approve the overload.',
],
[
'from' => 'sent', 'name' => 'You', 'time' => '9:20 AM', 'datetime' => '2026-11-02T09:20',
'message' => 'Please approve the overload, I need CSC 2110 this term.', 'status' => 'Delivered',
],
]" /><Chat
label="Conversation with your advisor"
:items="[
{
from: 'received', name: 'Pat Nguyen', time: '9:14 AM', datetime: '2026-11-02T09:14',
message: 'Your advising hold clears once you are under 12 credits or I approve the overload.',
},
{
from: 'sent', name: 'You', time: '9:20 AM', datetime: '2026-11-02T09:20',
message: 'Please approve the overload, I need CSC 2110 this term.', status: 'Delivered',
},
]"
/>Why it works this way
- An <ol> rather than a stack of divs, for the same reason Timeline is one: the sequence is the information (1.3.2). aria-live="polite" marks it as a region that grows, so an application that pushes a new message onto items gets it read out without moving focus, while a transcript that is only ever rendered once announces nothing extra, because a live region only speaks to changes made after it exists.
- The live region sits on the list itself rather than on a wrapping role="log", because a non-list role on the ol would leave its own li children with no list to belong to.
- Which side a bubble sits on is a visual convenience, not the only way to tell who is speaking. The name is always real text in the header, sent or received alike (1.4.1).
- This is on the internal template only. The example is a student asking their advisor about a hold, and an advisor relationship is exactly the thing the anonymous public catalog page does not have: nobody has signed in on it, and there is no one for a message to be from.
Accessibility
- aria-live="polite" on the list, so new messages are announced without moving focus (4.1.3).
- The name is text in the header regardless of which side the bubble is on (1.4.1).
- Each avatar is a real Avatar, named the same way it is everywhere else (1.1.1).
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 |
|---|---|---|
items | [] | [{ from, name, avatar, time, datetime, message, status }]. from is sent or received. |
label | 'Conversation' | Names the log for screen reader users. |
Vue
| Prop | Type and default | What it does |
|---|---|---|
items | Array, [] | [{ from, name, avatar, time, datetime, message, status }]. from is sent or received. |
label | String, 'Conversation' | Names the log for screen reader users. |
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-chat.
| Template | Elements | Accessibility attributes | Uses |
|---|---|---|---|
| internal apps/examples/static-html/index.html | ol | aria-labelaria-live | 1 |