Guide
Choosing a component
Pick by the need, not the look — every row below is a component the library already has.
Pick by the need, not the look. Everything below is an existing library component — never hand-roll what the catalogue already has. In a Razor page you always write <app-*>; the <wui-*> elements underneath are internal and wrapped by these.
A need → the component
| You need… | Use | Not |
|---|---|---|
| A primary / secondary / destructive action | <app-button variant> | a raw .btn |
| An icon-only action (edit/delete/more) | <app-action-icon> · <app-dropdown> | a bare icon button |
| A one-line text value | <app-input> (type, left-icon, unit, password) | raw <input> |
| Multi-line text | <app-textarea> | raw <textarea> |
| Pick one of 2–5 exclusive options, visible | <app-radio-group> · <app-choice-card> | a dropdown |
| Pick one of 6+ options | <app-select> (searchable past ~10) | a long radio list |
| Pick one from a large / remote list, type to find | <app-autocomplete> | a giant static select |
| Pick many options | <app-multi-select> (chosen shown as chips) | many checkboxes |
| A compact single-purpose picker (page size) | <app-select-mini> | <app-select> |
| A boolean on/off | <app-switch> | a checkbox as a toggle |
| Independent booleans | <app-checkbox> | switches |
| A selectable pill (filter toggle) | <app-choice-chip> | a styled button |
| A display / removable token (tag, chosen value) | <app-chip> (removable, tone) | <app-choice-chip> |
| A date | <app-date-picker> | raw <input type=date> |
| A phone number with country code | <app-phone-number-input> | input + separate select |
| A search box | <app-search> | <app-input> with a magnifier |
| File upload | <app-file-picker> · <app-file-attachment> · <app-logo-picker> | raw <input type=file> |
| A transient success / error message | WUI.toast(msg, { variant }) | a lingering inline alert |
| A persistent inline message | <app-alert variant> | a toast |
| A form's errors after a failed submit | <app-error-summary> | an alert that only counts the errors |
| A small count / label badge | <app-badge> | a styled span |
| A status pill (from a status enum) | <app-status-badge tone label> | <app-badge> |
| Loading placeholder | <app-skeleton> (loop it for table rows) | a full-page spinner |
| “Nothing here yet” | <app-empty-state> · <app-table-empty-state> | a bare message |
| A help tooltip beside a label | <app-info-tip> | title="" |
| A dialog (form / details) | <app-modal> | a bespoke overlay |
| A yes/no confirmation | <app-confirm-dialog> (danger for destructive) | <app-modal> hand-wired |
| App-wide search and jump (Ctrl+K) | <app-command-palette> (open with WUI.modal.open) | <app-modal> with a hand-wired list |
| A slide-in panel / drawer / mobile nav | <app-sidebar-menu> (side, responsive) | a hand-rolled drawer |
| Tabbed content | <app-tabs> · <app-accordion> | bespoke tabs |
| A content container | <app-card> | a .card div |
| A page masthead (title + subtitle + actions) | <app-page-header> | ad-hoc header markup |
| A user avatar (image / initials) | <app-avatar> | an <img> circle |
| A data grid with sorting / pagination | <app-data-table> + <app-table-pagination> | a hand-built <table> |
| Filters, search and bulk actions above a table | <app-table-toolbar> | a hand-built filter row |
| Letting people show or hide table columns | <app-column-menu> | a hand-built checkbox list |
Single-choice rule of thumb2–5 → radios / cards · 6–~15 → select · more or remote → searchable select / autocomplete · multiple → multiselect.
By category
| Actions | app-button, app-action-icon, app-dropdown |
| Text & number input | app-input, app-textarea |
| Choice & selection | app-select, app-select-mini, app-autocomplete, app-multi-select, app-checkbox, app-radio, app-radio-group, app-switch, app-choice-chip, app-choice-card |
| Tokens | app-chip (display/removable) — vs app-choice-chip (form control) |
| Specialized inputs | app-date-picker, app-phone-number-input, app-search, app-file-picker, app-file-attachment, app-logo-picker |
| Feedback & status | app-alert, app-error-summary, app-badge, app-status-badge, WUI.toast, app-skeleton, app-empty-state, app-table-empty-state, app-info-tip |
| Overlays | app-modal, app-confirm-dialog, app-command-palette, app-sidebar-menu |
| Layout & navigation | app-tabs, app-accordion, app-card, app-page-header, app-avatar, app-icon |
| Data | app-data-table, app-table-pagination, app-table-toolbar, app-column-menu |
Where the surfaces differNotifications are runtime-shaped: React has
toast(), Razor has WUI.toast(). <app-tabs> renders its own panels from <app-tab> children, where React renders the strip only. Both are deliberate — see the repo README.