Skip to content

Code block

A block of code with a button that copies it.

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-codeblock" data-wsu-codeblock data-wsu-codeblock-label="calendar subscription link">
  <div class="wsu-codeblock__head">
    <span class="wsu-codeblock__lang">webcal</span>
    <button class="wsu-btn wsu-btn--outline wsu-btn--sm wsu-codeblock__copy" type="button" data-wsu-codeblock-copy>
      <span class="wsu-codeblock__copy-state" data-wsu-codeblock-state="idle">
        <svg class="wsu-icon" aria-hidden="true"><use href="assets/wayne-ui/icons.svg#wsu-copy"/></svg>
        Copy
      </span>
      <span class="wsu-codeblock__copy-state" data-wsu-codeblock-state="copied" hidden>
        <svg class="wsu-icon" aria-hidden="true"><use href="assets/wayne-ui/icons.svg#wsu-check"/></svg>
        Copied
      </span>
      <span class="wsu-codeblock__copy-state" data-wsu-codeblock-state="failed" hidden>
        <svg class="wsu-icon" aria-hidden="true"><use href="assets/wayne-ui/icons.svg#wsu-circle-alert"/></svg>
        Press Control or Command C
      </span>
      <span class="wsu-sr-only">the calendar subscription link</span>
    </button>
  </div>

  <p class="wsu-codeblock__status wsu-sr-only" role="status" data-wsu-codeblock-status></p>

  <pre class="wsu-codeblock__pre" tabindex="0" role="region" aria-label="calendar subscription link"><code class="wsu-codeblock__code">webcal://calendar.wayne.edu/registration/ee6515.ics</code></pre>
</div>

Why it works this way

  • The copy button carries no script of its own. data-wsu-codeblock and data-wsu-codeblock-copy are read by the shared runtime in @waynestate/wayne-ui-css/theme, the same module the static, raw PHP and Blade paths load directly, so the clipboard behavior is one implementation rather than four. On the Vue path that runtime is wired up by useChromeRuntime, which AppShell calls, so a CodeBlock rendered outside an AppShell has a copy button that never copies anything.
  • The three outcomes, idle, copied and failed, are real elements in the markup, shown and hidden with the hidden attribute rather than written in by script, so a reader inspecting the DOM sees the same state a screen reader is told about. A separate role="status" carries the announcement, because a button whose own visible text changes while it already has focus is not guaranteed to be re-announced.
  • pre carries tabindex="0" and role="region", the same pairing the table's scroll wrapper uses. A line of code longer than the box scrolls horizontally, and a scrollable region with nothing else focusable inside it is otherwise unreachable by keyboard.

Accessibility

  • The copy button's visible label changes, but the announcement rides on a separate role="status" region rather than depending on the button being re-announced (4.1.3).
  • pre is a focusable, named region, so its horizontal scroll is reachable by keyboard (1.4.10, 2.1.1).
  • The failed state names the manual shortcut instead of leaving a reader stuck when the clipboard API is unavailable.

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
coderequiredThe literal text. Also what renders inside code.
lang''Shown above the code. Omit when there is none worth naming.
label'code'The noun the button and its announcement use.

Vue

PropType and defaultWhat it does
codeString, requiredThe literal text. Also what renders inside code.
langString, ''Shown above the code. Omit when there is none worth naming.
labelString, 'code'The noun the button and its announcement use.

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-codeblock.

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