App search
Search inside the application, not wayne.edu. A real form role="search" rather than a bare input, so it lands in the search landmark and submits on Enter with no script.
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.
<label class="wsu-sr-only" for="app-search">Search courses and students</label>
<form class="wsu-app-bar__search" role="search" action="/search" method="get">
<svg class="wsu-icon" aria-hidden="true"><use href="/assets/wayne-ui/icons.svg#wsu-search"/></svg>
<input class="wsu-app-bar__search-field" id="app-search" name="q" type="search"
placeholder="Search courses, students, sections"
aria-describedby="app-search-hint" data-wsu-search-hotkey>
<span class="wsu-sr-only" id="app-search-hint">Press Command or Control plus K to search</span>
<kbd class="wsu-app-bar__search-hint" aria-hidden="true">⌘K</kbd>
</form>
<!-- AppBar pairs the field above with this toggle and row, so the search is
not simply lost below the 768px breakpoint that hides the field itself. -->
<button class="wsu-btn wsu-btn--icon wsu-app-bar__toggle wsu-app-bar__search-toggle"
type="button" data-wsu-search-toggle="app-search-row">
<span class="wsu-sr-only">Search courses and students</span>
<svg class="wsu-icon" aria-hidden="true"><use href="/assets/wayne-ui/icons.svg#wsu-search"/></svg>
</button>
<div class="wsu-app-bar__search-row" id="app-search-row" hidden>
<label class="wsu-sr-only" for="app-search-narrow">Search courses and students</label>
<form class="wsu-app-bar__search" role="search" action="/search" method="get">
<svg class="wsu-icon" aria-hidden="true"><use href="/assets/wayne-ui/icons.svg#wsu-search"/></svg>
<input class="wsu-app-bar__search-field" id="app-search-narrow" name="q" type="search" placeholder="Search courses, students, sections">
</form>
</div>
<!-- Expandable, for a page whose masthead already carries a wayne.edu search box -->
<form class="wsu-app-bar__search wsu-app-bar__search--expandable" role="search" action="/catalog/search" method="get" data-wsu-search-expand>
<button class="wsu-app-bar__search-trigger" type="button">
<span class="wsu-sr-only">Search the course catalog</span>
<svg class="wsu-icon" aria-hidden="true"><use href="/assets/wayne-ui/icons.svg#wsu-search"/></svg>
</button>
<label class="wsu-sr-only" for="catalog-search">Search the course catalog</label>
<input class="wsu-app-bar__search-field" id="catalog-search" name="q" type="search" placeholder="Search courses and subjects" data-wsu-search-hotkey>
</form><x-wsu::app-search label="Search courses and students" placeholder="Search courses, students, sections"
action="/search" hotkey />
{{-- Expandable, for the public template. hotkey defaults to true, same as
above, so Command or Control plus K still focuses the field once it is
open; there is just no visible kbd glyph to draw while it is collapsed. --}}
<x-wsu::app-search variant="expandable" id="catalog-search"
label="Search the course catalog" placeholder="Search courses and subjects"
action="/catalog/search" /><AppSearch
label="Search courses and students"
placeholder="Search courses, students, sections"
action="/search"
hotkey
/>
<!-- Expandable, for the public template. hotkey defaults to false here,
unlike the Blade path, so it is set explicitly to keep the two samples
in step: Command or Control plus K still focuses the field once open. -->
<AppSearch
id="catalog-search"
label="Search the course catalog"
placeholder="Search courses and subjects"
action="/catalog/search"
expandable
hotkey
/>Why it works this way
- Two shapes. inline is a permanent field, used on the internal template where nothing else on the bar competes for the space. expandable rests as an icon and grows into a field, used on the public template, where the official masthead above already carries a wayne.edu search box: two full fields side by side, searching different things, is a confusing thing to put in front of someone.
- The hint sentence, "Press Command or Control plus K to search", is read through aria-describedby rather than the visible kbd glyph, because a screen reader announces ⌘K as loose letters or nothing at all. The glyph itself is aria-hidden and shown only on the inline field, which has room for it; the expandable field has none while collapsed.
- The growth animation on the expandable variant and the Cmd/Ctrl+K shortcut both belong to wayne-ui-css/theme, wired off data-wsu-search-expand and data-wsu-search-hotkey. No path ships script of its own for this.
- action left empty renders a same-page field: the Vue component emits submit instead of navigating. The Blade and static paths always need a real action, since neither has a script waiting to intercept the submit.
- chrome.css hides the plain inline field below the 768px medium breakpoint, since at that width it would crowd out the application name. AppBar is what pairs it with a toggle button and a full-width row that unfolds beneath the bar, so nothing is lost; a bare inline field with neither, the way it would appear rendered on its own below that width, is a field that has simply disappeared.
Accessibility
- role="search" on a real form, so the field lands in the search landmark and Enter submits it without a keydown handler (1.3.1).
- The shortcut requires a modifier, Command or Control plus K, never a bare letter: a bare key fires while someone dictating text by voice is in the middle of a different word (2.1.4).
- On the expandable variant the trigger button carries the accessible name while the field does not exist yet; once expanded, a visually hidden label names the field on its own rather than depending on the trigger having ever been there.
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 |
|---|---|---|
variant | 'inline' | "inline" or "expandable". |
id | 'app-search' | id of the field, and the prefix for the hint id. |
label | config('wayne-ui.search.label') | Accessible name for the field, and for the trigger when expandable. |
placeholder | config('wayne-ui.search.placeholder') | Shown in the field. |
action | config('wayne-ui.search.action') | Omit for a same-page search with no navigation. |
method | config('wayne-ui.search.method') | Form method. |
name | config('wayne-ui.search.name') | Query parameter name. 'q' matches the rest of the university's search endpoints. |
value | the current query string | Falls back to request()->query() for the field's own name. |
hotkey | config('wayne-ui.search.hotkey') | Advertises and enables Command or Control plus K. |
hint | the shortcut sentence | Spoken description of the field, via aria-describedby. Defaults to the shortcut sentence when hotkey is set. |
Vue
| Prop | Type and default | What it does |
|---|---|---|
modelValue | String, '' | v-model. |
label | String, 'Search this application' | Accessible name for the field, and for the trigger when expandable. |
placeholder | String, 'Search' | Shown in the field. |
name | String, 'q' | Query parameter name. 'q' matches the rest of the university's search endpoints. |
method | String, 'get' | Form method. |
expandable | Boolean, false | Rests as an icon and grows into a field. |
hotkey | Boolean, false | Advertises and enables Command or Control plus K (2.1.4). |
hint | String, '' | Spoken description of the field. Defaults to the shortcut sentence when hotkey is set; otherwise set it where the field needs distinguishing from another search box on the page. |
id | String, '' | id of the field. Generated when omitted; set it when something else on the page needs to reference the field directly. |
action | String, '' | Omit to emit submit instead of navigating. |
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-app-bar__search.
| Template | Elements | Accessibility attributes | Uses |
|---|---|---|---|
| internal apps/examples/static-html/index.html | buttondivforminputkbd | aria-describedbyaria-hiddenhiddenrole | 7 |
| public apps/examples/static-html/public-app.html | buttonforminput | aria-describedbyrole | 3 |