Page Toolbar

.page-toolbar

Top control strip of a workspace: search, actions, density and view controls on one wrapping row. Put it inside a .card-header or directly above the grid. Bootstrap dependencies: none — it is a flex row, so gap-*, ms-auto and order-* utilities work on its children.

⌘K

Compact — add .page-toolbar-compact on an ancestor to shrink every control in the strip.

Disabled & long content — buttons take the native disabled attribute; long labels wrap to the next row rather than overflowing.

Quick Filters
.quick-filters

Inline filter pills with a result count. Use for the four or five filters people reach for most; anything longer belongs in a filter drawer. Set aria-pressed so screen readers announce the active state.

Filter Chips
.filter-chips

The applied-filter summary. Each chip carries its own dismiss button; the container collapses to nothing when empty, so it can stay in the markup permanently.

Class: III-A Status: Active Admitted after 01 Jan 2024

Empty — an empty container renders nothing, no conditional markup needed.

Summary Strip & Summary Card
.summary-strip · .summary-card

Headline figures above a grid. The strip is an eight-column grid that steps down to four, two and one across breakpoints. Tone comes from the global accent modifiers — .accent-primary, .accent-success, .accent-warning, .accent-danger, .accent-info, .accent-purple, .accent-teal — never from a page-level colour.

248Total students
212Active
14Pending
6Suspended
18Classes
93%Attendance
$41kCollected
Consolidated term performanceLong content clamps instead of overflowing
Record Grid
.record-grid-wrapper · .record-grid-table · .record-grid-row

The workspace table. .record-grid-wrapper owns the horizontal scroll, .record-grid-table the layout, and each <tr> takes .record-grid-row. Sorting uses .record-sortable plus .is-sorted-asc / .is-sorted-desc; the first column can stick with .is-pinned; a chosen row takes .is-selected. Identity cells combine .record-identity, .record-avatar and .record-tag / .record-pill.

Student Class Status Attendance Actions
Janet DanielAD1256589
III-A Active
Joann MichaelAD1256590
IV-B Pending
Kathleen Moreno — transferred from St. Andrews Senior SecondaryLong content truncates rather than widening the column
V-A Suspended

Loading — swap the grid for the global skeleton loader. There is one skeleton system template-wide; never write a per-page variant.

Empty.workspace-empty-state is hidden until it gets .show, so it can sit in the markup permanently.

No records match these filters

Try widening the date range or clearing a filter chip.

Record Cards
.record-cards · .record-card

The responsive counterpart of the grid — the same record shown as a card once the table is too wide for the viewport. Pair it with the view switcher, or let it take over below the grid's breakpoint.

Janet DanielIII-A · AD1256589
Active
Attendance94%
GuardianThomas Daniel
Selection Toolbar
.selection-toolbar

Appears when rows are selected — add .show to reveal it. Keep destructive actions last and announce the count with aria-live="polite".

3 selected
Quick Menu .quick-menu

The dropdown panel behind a workspace action button.

Bulk actionsApplies to the 3 selected records
Details Panel
.details-panel · .details-panel-block · .details-panel-row

The expanded view of a record, either inline under its row (toggled by .details-toggle) or in an offcanvas. The panel is a grid of blocks; a page may override the column count, nothing else.

Personal
Date of birth14 Mar 2016
GenderFemale
Blood groupO+
Academic
ClassIII-A
Roll number35013
Admitted18 Mar 2024
Contact
GuardianThomas Daniel
Phone+1 4587 3312
Address2831 Sherwood Circle, Cheyenne, Wyoming — long values wrap inside the row
Workspace Footer & Pagination
.workspace-footer · .workspace-pagination

Closes the workspace: result count and page-size selector on the left, pagination on the right. Wrap the control in <nav aria-label="Pagination"> and mark the current page with aria-current="page".

Upload Dropzone
.upload-dropzone

Import panel for bulk record uploads. Add .dragover while a file is over the target. Always pair it with a real <input type="file"> so keyboard users can browse.

Live Content
.live-content

The counterpart to the skeleton loader: content inside .live-content stays hidden until the workspace root gains .is-loaded, so the two never flash at once.

<div class="students-workspace">
  <div class="skeleton-loader">…</div>
  <div class="live-content">…</div>
</div>

// when data arrives
root.classList.add("is-loaded");
Workspace Actions
.workspace-actions

A trailing group of related buttons — inside a card header, a row, or the details panel.

Component reference
ComponentPurposeModifiers & statesNotes
.page-toolbarWorkspace control strip.page-toolbar-compactFlex row — Bootstrap spacing and order utilities apply
.search-toolbarSearch field with icon and shortcut hint.search-toolbar-icon, .search-toolbar-kbdWraps a Bootstrap .form-control
.summary-strip / .summary-cardHeadline figures above a gridAny .accent-*8 → 4 → 2 → 1 columns by breakpoint
.selection-toolbarBulk actions for selected rows.showCount needs aria-live="polite"
.record-grid-wrapperHorizontal scroll containerOwns the scroll; never set overflow on the table
.record-grid-tableWorkspace table.record-sortable, .is-sorted-asc, .is-sorted-desc, .is-pinnedColumn widths are page overrides
.record-grid-rowRecord row.is-selectedPair with .record-check
.record-cards / .record-cardCard view of the same record.record-card-head, -body, -actionsResponsive fallback for the grid
.record-identityAvatar plus name and sub-label.record-identity-name, -subTruncates instead of widening the column
.record-avatarRecord thumbnail.record-avatar-presenceAccepts .accent-* for the presence tone
.record-tag / .record-pillInline status marker.record-pill-dot, any .accent-*Use Bootstrap .badge for non-record contexts
.filter-chips / .filter-chip-itemApplied-filter summary.filter-chip-clearCollapses when empty
.quick-filters / .quick-filterInline filter pills.active, .quick-filter-count, disabledSet aria-pressed
.quick-menuDropdown action panel-head, -head-title, -head-sub, -icon, -listDrop inside a Bootstrap .dropdown-menu
.details-panelExpanded record view-block, -row, -photo, .details-toggleColumn count may be overridden per page
.workspace-footerResult count and page size-info, -sizeSits directly under the grid
.workspace-paginationPage navigation.workspace-page-button, -numbers, -gap, .activeWrap in <nav aria-label>, mark aria-current="page"
.workspace-button / .workspace-icon-buttonToolbar controls.active, disabled, .workspace-button-iconIcon-only buttons need aria-label
.workspace-actionsTrailing button groupUse gap-* to adjust rhythm
.density-toggle / .view-switcherRow density and list/grid switch.activeUse role="group" with a label
.workspace-empty-stateNo-results state.show, .workspace-empty-artHidden until .show is added
.skeleton-loader / .skeletonLoading placeholder-line, -thin, -avatar, -circle, -pill, -card, -btn, -stackThe template's only skeleton system
.live-contentReal content, revealed on loadRoot .is-loadedPairs with the skeleton loader
.upload-dropzoneBulk import target.dragover, -title, -hintAlways back it with a real file input
.id-card-previewPrintable ID card preview.id-card-head, -identity, -info, -row, -qr, -barcode, -footFixed aspect; scales with its container

Every component above inherits colour, radius, shadow and motion from the global design tokens — --bs-* for the brand palette, --radius*, --shadow*, --transition, --accent* and --tint-*. None of them declares a colour of its own, so they follow the theme and dark mode automatically. Do not add page-level colour, spacing or typography overrides; restrict page SCSS to genuine layout differences.