Common app interface pieces built from Bootstrap 3.3.7, the
version cdn.ucsd.edu serves: tabs, side menus, toolbars and item bars, action
menus, lists, pagination, dialogs, and responsive helpers. Each one has a live preview and
a prompt you can copy. Further down: dashboard building blocks, seven complete app shells,
and eight starter dashboards for campus areas.
Read the tags first
Bootstrap loads on every Decorator page, but the Decorator restyles only part of it.
Each pattern carries one of these tags:
Decorator-styled The
Decorator stylesheet already styles it. Use the markup as is.
Neutral Layout, gray borders,
and link color only. Safe to use as is.
Brand layer Stock Bootstrap would
paint it #337ab7 blue. Add the matching block from
css/app-patterns.css, which
re-colors it to the Decorator palette in the canvas only.
Bootstrap docs Not in the
Decorator package. The markup comes from Bootstrap v3.3.7's own documentation
source (twbs/bootstrap, tag v3.3.7,
docs/_includes/).
Add the brand layer to a project
Run this once before you use any pattern tagged Brand layer.
Prompt
Add css/app-patterns.css to the project, copied from the Decorator Kit Developer Guide, and link it in the "site-specific CSS" block of each page that uses app patterns. Every rule must stay scoped under main#main-content plus an app-* class. Key active states on aria-current, aria-expanded, or :checked. Never target .active, .nav, .dropdown-menu, .btn-default, or any other class the header, navbar, or drawer uses.
These patterns move between views inside your app, within the canvas.
They don't replace the site navbar, drawer, or side nav, which are chrome.
Tabs
Switch between related views without leaving the page. bootstrap.min.js
(tab.js) handles switching and sets aria-expanded. No custom
JavaScript needed.
12 open requests · 3 due this week · last sync 9:41 a.m.
Your request history appears here.
Notification and display preferences.
Prompt
Add Bootstrap 3.3.7 togglable tabs (the markup from the Bootstrap docs' js/tabs example) with the tabs [Overview, Requests, Settings]. Use ul.nav.nav-tabs.app-tabs with role="tablist", role="tab" on each link, and a matching div.tab-pane role="tabpanel" with aria-labelledby. Keep aria-expanded="true" on the first tab. Switching comes from data-toggle="tab", so don't write tab JavaScript. Leave out the dropdown-inside-a-tab variant.
Side menu
A vertical menu for an app's sections, built from a linked list group in a
.col-sm-3 column. On phones it stacks above the content. Mark the
current item with aria-current="page", not .active.
Brand layerBootstrap docs · list-group
nav > .list-group.app-sidemenua.list-group-itemaria-current="page".badge
Live preview
Inbox
The selected view's content goes in the wider column.
Prompt
Inside the canvas, make a two-column app layout: a .row with a .col-sm-3 side menu and a .col-sm-9 content area. The side menu is a <nav aria-label="[App name]"> wrapping div.list-group.app-sidemenu with a span.list-group-item.app-sidemenu-heading, then one a.list-group-item per section: [Inbox (count), Assigned to me (count), Waiting, Closed, Settings]. Mark the current item with aria-current="page", not .active. Show counts with span.badge. Include the side-menu and badge blocks from css/app-patterns.css. This is an in-app menu. Don't change article.main-content-nav.
Segmented control (view switcher)
A single-choice toggle such as List / Grid / Calendar, or Day / Week / Month.
Real radio inputs keep it keyboard and screen-reader friendly.
button.js handles the toggling.
Add a view switcher: div.btn-group.app-segmented with data-toggle="buttons", role="group", and aria-label="View". Put one label.btn with a radio input (shared name, autocomplete="off") for each option: [List, Grid, Calendar]. Pre-check the first and give its label .active. Each label gets a Glyphicon (aria-hidden) plus visible text. Include the segmented block from css/app-patterns.css. Listen for the radio change event in js/[app].js to switch the view.
A bar of grouped actions above a list or table. On the left: a selection count
and bulk actions. On the right: an in-app search. Icon-only buttons need an
aria-label.
Above the [requests table], add an item bar: div.btn-toolbar.app-toolbar with role="toolbar" and aria-label="[Request actions]". Contents, in order:
1. span.app-toolbar-count showing "[n] selected". Update it from js/[app].js and announce changes in an aria-live region.
2. A .btn-group of button.btn.app-tool: [Approve, Archive, Delete]. Icon-only buttons get aria-label.
3. A "More" dropdown (btn-group + dropdown-toggle + ul.dropdown-menu, following kitchen-sink/button_dropdowns.html) with [Export as CSV, Assign to…, Mark all as read].
4. A right-aligned form.app-toolbar-search with role="search": an .sr-only label, an input-group with input.app-search-input, and an icon submit button.
Include the toolbar block from css/app-patterns.css. Glyphicons only. This search filters the app, not the site. Leave the chrome search forms alone.
Add a "[New request]" dropdown button using the single-button dropdown from kitchen-sink/button_dropdowns.html, with btn-primary (not btn-success or others). Add aria-haspopup="true" and aria-expanded="false" to the toggle. Menu items: [..], then a li.divider with role="separator", then [..]. Don't add CSS for .dropdown-menu — the Decorator already styles it.
Render [requests] as a linked list group: div.list-group.app-list with one a.list-group-item per item, each holding h4.list-group-item-heading "[id · title]", p.list-group-item-text "[unit · date · status]", and an optional span.badge for unread counts. State status in words — don't use list-group-item-success/-info/-warning/-danger. Include the list and badge blocks from css/app-patterns.css. Escape all data before inserting it.
Media list (people, comments, activity)
An image or avatar beside a text block. For comment threads, activity feeds,
and people pickers.
Plumber scheduled for tomorrow morning. The area is roped off.
Sam Rivera
Requester · Yesterday
Thanks! The sink on the 3rd floor has the same problem.
Prompt
Show the [comment thread] as a Bootstrap 3 media list (the markup from the Bootstrap docs' media example): ul.media-list with one li.media.app-media per entry, containing .media-left > img.media-object.img-circle (64 × 64, alt="" because the name is next to it) and .media-body with h4.media-heading [name], p.app-media-meta [role · time], and the text. Include the media block from css/app-patterns.css. Escape user text before rendering it.
Pagination
Page through long lists. Stock Bootstrap paints the current page #337ab7 and
the links are only 34px tall. The brand layer re-colors them and makes each
link a 44 × 44 touch target.
Add pagination under the [list] following kitchen-sink/pagination.html: nav aria-label="[Request pages]" > ul.pagination.app-pagination. Mark the current page with aria-current="page" on its link, not li.active. The previous/next links get aria-label ("Previous page", "Next page") with aria-hidden arrows. Include the pagination block from css/app-patterns.css.
A confirmation or short form that needs a decision before the user continues.
modal.js handles focus, the Esc key, and the backdrop. Keep the
modal markup inside the canvas.
Add a confirmation dialog using the Bootstrap 3.3.7 modal markup from the Bootstrap docs' js/modal example: div.modal.fade.app-modal with tabindex="-1", role="dialog", and aria-labelledby pointing at the h4.modal-title id. The close button gets aria-label="Close". Footer buttons: btn-default "[Cancel]" (data-dismiss="modal") and btn-primary "[Close request]". Open it from a button with data-toggle="modal" data-target="#[id]". Put the modal markup at the end of main#main-content, not in the chrome. Wire the confirm action in js/[app].js. Include the modal block from css/app-patterns.css.
Expand and collapse
For FAQs and grouped details, use the Decorator drawer, which
base.min.js already runs. Use Bootstrap's panel-group accordion
only when you need its events.
Decorator-styled
.drawer-wrapper.drawer
Prompt
For the expandable [details] section, use the Decorator drawer (.drawer-wrapper > .drawer with h2 > a / div pairs, from templates/modules.html), not a Bootstrap panel-group accordion.
You're on xs (phone)You're on sm (tablet)You're on md (laptop)You're on lg (desktop)
Prompt
On phones (xs), hide the [toolbar's text labels] with .hidden-xs and keep the icons. Every icon-only button needs an aria-label. Use Bootstrap 3 responsive utilities (visible-*-block/-inline/-inline-block, hidden-*). Don't write media queries for what these classes already do.
Helper class reference
Colorless Bootstrap helpers that are safe anywhere in the canvas, plus the
ones to avoid.
Bootstrap 3.3.7 helper classes
Class
Use it for
Status
.sr-only, .sr-only-focusable
Text for screen readers only, such as labels for icon buttons and hidden form labels
Safe
.pull-left, .pull-right, .clearfix
Floating a small element and clearing it
Safe (not on the two-column split)
.center-block, .text-left/-center/-right
Centering blocks and aligning text
Safe
.list-unstyled, .list-inline
Removing bullets and inline link rows
Safe
.img-responsive, .img-rounded, .img-circle
Fluid images and avatars
Safe
.embed-responsive.embed-responsive-16by9
A true 16:9 video box inside an app. Modules use .embed-video
Safe
.visible-*, .hidden-*, .hidden-print
Showing and hiding by breakpoint, and for print
Safe
.text-muted, .small
Secondary text (gray #777)
Neutral. Check contrast
.text-*/.bg-* with -success/-info/-warning/-danger
—
Avoid: stock Bootstrap colors
.label-*, .progress-bar, .nav-pills active
—
Avoid, or add a canvas brand layer
title="" tooltips (tooltip.js)
—
Avoid: unreachable by keyboard and touch. Use visible help text
Prompt
Prefer Bootstrap 3.3.7 helper classes (sr-only, text-center, pull-*, clearfix, list-inline, img-circle, embed-responsive, visible-*/hidden-*) over new CSS. Don't use any -success/-info/-warning/-danger class, .label-*, .progress-bar, or title-attribute tooltips. Replace tooltips with a visible .help-block.
Six small pieces that almost every dashboard reuses. None needs a charting library.
Each one shows its value as text, so it works without color and with a screen reader.
The styles live in css/app-patterns.css.
Key number with trend
A headline number, what it measures, and how it changed. The arrow is decorative.
The words "up" and "down" carry the meaning.
Add a row of [3] key numbers: .col-sm-4 columns, each a div.styled.app-stat with span.app-stat-value, span.app-stat-label, and span.app-trend. The trend is a Glyphicon arrow (aria-hidden) plus words: "Up 6% from August", "Down 20 min (better)", or "No change". Never show a trend by color alone. Include the KPI block from css/app-patterns.css.
Data bars
A labeled horizontal bar for comparing a few values: fill rate, occupancy, budget
used. The number is printed beside every bar, and the bar itself is hidden from
screen readers. For more than about 10 rows, or real charts, use a table or a
charting library from canvas-components/.
Show [occupancy by college] as data bars: a div.app-panel with p.app-panel-title, then ul.app-bars labelled by that title. Each li holds span.app-bar-label, span.app-bar-track (aria-hidden="true") containing span.app-bar-fill with the nearest 5% width class (app-w-0 … app-w-100), and span.app-bar-value with the exact number. Use .app-bar-attn to highlight a row, but say why in text too. No inline style widths — set the class from JS.
Status list
A list of named things, each with a status badge. Four states use only Decorator
colors, and every state is spelled out in words.
UCSD-PROTECTED Wi-Fi DegradedSlow connections in Geisel. Engineers are on site.
Print stations Outage
VPN Maintenance Sat 6 a.m.
Prompt
List [services] as ul.list-group.app-status-list. Each li.list-group-item has span.app-status-name, a span.app-status with data-status set to ok, warn, down, or info (a Glyphicon plus the words "Operational", "Degraded", "Outage", or "Maintenance [when]"), and an optional span.app-muted detail line. Don't use label-*, list-group-item-success/-warning/-danger, or any other Bootstrap contextual class.
Deadline timeline
What's coming up, in date order. Urgent items get a gold marker plus the word
"urgent" for screen readers.
Show upcoming [deadlines] as ol.app-timeline in date order. Each li has span.app-timeline-date (a <time datetime> plus "· [time remaining]"), span.app-timeline-title, and span.app-muted context. Items due within [7] days get data-urgent and an .sr-only "(urgent)". Compute the time remaining in js/[app].js from the datetime values.
Checklist progress
A read-only list of steps with a summary line and a data bar. For onboarding,
closeouts, and move-in. Use real checkboxes if people check items off on this
screen.
Brand layer
ul.app-checklistli[data-done]ul.app-bars
Live preview
Onboarding: Alex Kim, Programmer Analyst
3 of 5 done60%
Offer letter signed (done)
Background check cleared (done)
Active Directory account (done)
Cyber-security training (to do)
Parking permit (to do)
Prompt
Show [onboarding] progress in a div.app-panel: p.app-panel-title "[person, role]", a one-row ul.app-bars "[n] of [total] done", then ul.app-checklist. Done items get data-done, a glyphicon-check, and an .sr-only "(done)". Open items get glyphicon-unchecked and "(to do)". If people check steps off on this screen, use real labeled checkboxes instead.
Filter bar
Scopes the whole dashboard: term, unit, date range. Labels stay visible, and every
control is at least 44px tall.
Add a filter bar at the top of the dashboard: form.app-filterbar with aria-label="Dashboard filters". Each control is a .form-group with a visible label and a .form-control.app-filter-control: [Term select, College select, From date, To date], then a btn-primary "Apply". Keep the filters in the URL query string so views can be bookmarked, but never put personal data in it. Update the page from js/[app].js and announce "Showing [scope]" in an aria-live region.
Complete app screens, each combining several of the patterns above. Every shell has
a live preview, the build order from top to bottom, and one prompt that builds the whole
screen. Start from the closest one and change the placeholders.
Create [requests.html] from blank-slate.html for a [request manager] app. Add it to the drawer and the navbar. Link css/app-patterns.css (copied from the Decorator Kit Developer Guide) in the site-specific CSS block.
Canvas, inside div.app-shell:
1. Item bar (div.btn-toolbar.app-toolbar, role="toolbar"): [New], bulk [Archive, Refresh] icon buttons with aria-labels, and a right-aligned in-app search form.
2. A .row: a .col-sm-3 side menu (nav > .list-group.app-sidemenu with [Inbox, Assigned to me, Closed] and badge counts, current item marked aria-current="page") and a .col-sm-9 work area.
3. In the work area: Bootstrap tabs (ul.nav.nav-tabs.app-tabs, role="tablist") for [Open, Due soon]. Each tab panel holds a .list-group.app-list of requests and a nav > ul.pagination.app-pagination.
4. A "Close request" modal (.modal.fade.app-modal) at the end of the canvas.
Load the data from [requests.json] in js/requests.js and escape every value. Use Bootstrap 3.3.7 data-api behaviors (tab, dropdown, modal, buttons) — no other JS framework. No -success/-info/-warning/-danger classes. Status is always written in words.
Operations dashboard
The at-a-glance home screen of an internal tool: headline numbers, what needs
attention, and recent activity.
Template: blank-slate.html
View header with a "last updated" line and a refresh button
Four stat boxes (div.styled.app-stat) in a .row
.msg.alert that appears only when something needs attention
Two columns: a table.styled-dark of items due and a media list of recent activity
Create [dashboard.html] from blank-slate.html for the [Facilities] dashboard. Add it to the drawer and the navbar. Link css/app-patterns.css.
Canvas, inside div.app-shell:
1. div.app-view-head with h4.app-view-title "[Facilities Dashboard]", an "Updated [time]" span.app-muted, and an icon refresh button (aria-label="Refresh dashboard").
2. A .row of four .col-xs-6.col-md-3 stat boxes, each a div.styled.app-stat with span.app-stat-value and span.app-stat-label: [Open requests, Due today, Overdue, Avg. time to close].
3. A .msg.alert only when overdue > 0, with a link to the overdue list.
4. A .row: .col-md-7 with a table.styled-dark.app-table "Due today" (caption, th scope="col", tr.even on alternate rows) and .col-md-5 with a ul.media-list of recent activity (li.media.app-media, avatar alt="").
Load data from [dashboard.json] in js/dashboard.js, escape every value, and announce refreshes in an aria-live region. Status is words, never color alone. No -success/-info/-warning/-danger classes, no progress bars.
Data admin table
Manage a list of records in bulk: select rows, act on them, switch views, and
page through.
Template: blank-slate.html · for sorting and search at scale, swap in the DataTables widget
View header with a primary "Add" action menu
Item bar: selection count, bulk actions, view switcher, search
table.styled-dark with a checkbox column (each with an .sr-only label)
Create [rooms.html] from blank-slate.html for a [room inventory] admin tool. Add it to the drawer and the navbar. Link css/app-patterns.css.
Canvas, inside div.app-shell:
1. div.app-view-head: h4.app-view-title "[Room Inventory]" and a btn-primary "Add" dropdown (dropdown-menu-right) with [Single room, Import from CSV].
2. Item bar (div.btn-toolbar.app-toolbar, role="toolbar"): span.app-toolbar-count "[n] selected", bulk [Edit, Export] app-tool buttons, a .btn-group.app-segmented radio filter [All, Available], and a right-aligned in-app search form.
3. table.styled-dark.app-table in .table-responsive: a first column of checkboxes, each with its own .sr-only label ("Select [room]"), and a "Select all" checkbox in the header. Columns: [Room, Building, Seats, Status]. Status in words. tr.even on alternate rows.
4. div.app-view-head with "Showing x–y of n" and nav > ul.pagination.app-pagination (aria-current="page").
In js/rooms.js: keep the selection count and "Select all" in sync, announce changes in an aria-live region, and escape every value. If sorting or search across more than ~200 rows is needed, use the DataTables widget (widgets/datatables.html) for the table instead.
Settings and profile
Sectioned preferences with a side menu, grouped form fields, and one save bar.
Template: two-column.html or blank-slate.html
Side menu of settings sections (current one marked aria-current)
Form grouped with fieldset/legend
Segmented control for a single choice, checkboxes for toggles
.app-savebar with Cancel / Save, and a .msg.info confirmation after saving
Forms · .msg.infoBrand layer
Live preview
Notifications
Saved
Your notification settings were updated.
Prompt
Create [settings.html] from [two-column.html] for the app's settings. Add "Settings" to the drawer, the navbar, and the side nav. Link css/app-patterns.css.
Canvas, inside div.app-shell, as a .row:
1. .col-sm-3: nav aria-label="Settings sections" > .list-group.app-sidemenu with a heading and [Profile, Notifications, Accessibility, Connected apps]. The current section gets aria-current="page".
2. .col-sm-9: h4.app-view-title for the section, then a form. Group related fields in fieldset.app-facet with a legend: checkboxes for on/off options, a .btn-group.app-segmented radio group for single choices, and .form-group/.form-control inputs with labels and autocomplete. Help text goes in .help-block, linked with aria-describedby.
3. div.app-savebar at the end: btn-default "Cancel" (reset) and btn-primary "Save changes".
After a successful save, show a .msg.info "Saved" above the form and move focus to it. Show validation errors above the form in a .msg.alert. Submit logic goes in js/settings.js, with a CSRF token.
Multi-step application
A longer form split into steps, with a visible step indicator and
Back / Continue controls. For a full wizard with validation per step, use the
Wizard widget.
Step indicator (ol.app-steps, with the current step marked aria-current="step" and completed steps named in text)
The current step's fieldset
Save bar with Back, Save draft, and Continue
FormsBrand layer
Live preview (static)
Research Funding Application
Applicant (completed)
Project
Budget
Review
Prompt
Create [apply.html] from blank-slate.html for a [4]-step [funding application]. Link css/app-patterns.css.
Canvas, inside div.app-shell:
1. h4.app-view-title "[Research Funding Application]".
2. ol.app-steps with aria-label="Application progress" and one li per step: [Applicant, Project, Budget, Review]. The current step gets aria-current="step". Completed steps get data-state="done" plus an .sr-only "(completed)".
3. One fieldset.app-facet per step, with legend "Step n of 4: [name]" and Bootstrap 3 form fields (labels, autocomplete, help-block linked via aria-describedby). Show only the current step's fieldset.
4. div.app-savebar with btn-default "Back", btn-default "Save draft", and btn-primary "Continue" ("Submit" on the last step).
In js/apply.js: validate each step before advancing, show errors above the form in a .msg.alert, move focus to the new step's legend, and update aria-current. Save drafts to [endpoint] with a CSRF token. If the steps need branching or per-step validation UI, use the Wizard widget (widgets/wizard.html) instead.
Record detail
A single item's page: what it is, what happened to it, and what you can do next.
Template: two-column.html
Breadcrumb back to the list (the template's breadcrumb, pointed at real pages)
Header: title, status in words, and an Actions dropdown
Tabs: Details (dl.dl-horizontal), Activity (media list plus a comment form), Files (item list)
Create [request-detail.html] from two-column.html as the detail view for one [request]. Set the breadcrumb to Home › [Requests] › [RQ-id], resolved from this page's folder. Link css/app-patterns.css.
Canvas, inside div.app-shell:
1. div.app-view-head: h4.app-view-title "[id · title]", a span.app-muted line with the status in words plus who opened it and when, and a btn-primary "Actions" dropdown (dropdown-menu-right) with [Reassign…, Change due date…, divider, Close request…]. "Close request…" opens a .modal.fade.app-modal confirmation.
2. Bootstrap tabs (ul.nav.nav-tabs.app-tabs, role="tablist"):
- Details: dl.dl-horizontal.app-details with [Location, Category, Assigned to, Due].
- Activity (with a count badge): ul.media-list of comments (li.media.app-media), then a comment form with a labeled textarea and a btn-default "Post comment".
- Files: .list-group.app-list of attachments with a Glyphicon and size.
Load the record from [api/requests/:id] in js/request-detail.js. Escape all user text, and send comments with a CSRF token.
Search with filters
Search results for a catalog, directory, or knowledge base, with filter facets,
a result count, and an empty state.
Template: blank-slate.html
A large in-app search bar (not the site search)
Filter facets as checkbox fieldsets in a side column
Result count (announced to screen readers), a sort dropdown, and an item list
Empty state: No courses match. Try removing a filter or checking the spelling.
Prompt
Create [courses.html] from blank-slate.html for [course] search. Add it to the drawer and the navbar. Link css/app-patterns.css.
Canvas, inside div.app-shell:
1. An in-app search form (role="search"): a visible label, then .input-group.input-group-lg with input.form-control.app-search-input and a btn-primary "Search". Leave the chrome search forms alone.
2. A .row: .col-sm-3 holds the filter facets — a form aria-label="Filter results" with one fieldset.app-facet per facet [Level, Quarter], each a legend plus labeled checkboxes showing counts. The .col-sm-9 holds the results.
3. Results header (div.app-view-head): a role="status" line "[n] results for “[query]”" and an app-tool "Sort" dropdown (dropdown-menu-right) with [Relevance, Course number, Seats available].
4. .list-group.app-list results (h5.list-group-item-heading + p.list-group-item-text), then nav > ul.pagination.app-pagination.
5. With zero results, replace the list with div.app-empty: a Glyphicon (aria-hidden) and a suggestion.
In js/courses.js: update results when filters change without a page reload, keep the query and filters in the URL, and escape every value.
Starter dashboards for the kinds of internal tools UC San Diego units build most often.
Each one names who it's for and the data it touches, and combines the building blocks and
patterns above. All names and numbers are made up.
Before you connect real data
Many of these dashboards show protected data: FERPA student records, personnel
records, research budgets. Put them behind campus Single Sign-On, check authorization on
every request, keep personal data out of URLs and logs, and treat anything you're
unsure of as sensitive. Every prompt below includes these rules, so leave them in.
Build a dashboard with an agent, in four prompts
Don't ask for the whole app at once. Send these four prompts in order, and review
the result of each before you send the next. Paste the dashboard prompt of your
choice into step 2.
Step 1 · Scaffold
Create [dashboard.html] from blank-slate.html (from node_modules/ucsd-decorator-v5/dist/templates). Rewrite every CSS and script path to cdn.ucsd.edu. Add "[Dashboard name]" to the drawer and the navbar, leaving both search blocks as shipped. Copy css/app-patterns.css from the Decorator Kit Developer Guide and link it in the site-specific CSS block. Create an empty js/[dashboard].js and load it after base.min.js. Stop there, and show me the diff.
Step 2 · Static layout
Inside main#main-content only, build the static layout below using hard-coded sample data that is obviously fake. Use the Decorator and app-patterns classes named in it. No JavaScript yet.
[paste one dashboard prompt from the Developer Guide here]
Step 3 · Wire the data
In js/[dashboard].js, replace the sample data with data from [endpoint]. Keep the static markup as the no-JavaScript fallback where you can. Build DOM nodes with textContent (never innerHTML with data), set data-bar widths with app-w-* classes, and announce refreshes and filter changes in one aria-live region. The endpoint requires campus SSO. Handle 401/403 by showing a .msg.alert with a sign-in link, and handle empty results with an .app-empty state. Don't log response bodies.
Step 4 · Review and verify
Review [dashboard.html]:
- Did anything change outside main#main-content? Are all Decorator assets loaded from cdn.ucsd.edu?
- Any -success/-info/-warning/-danger, label-*, progress-bar, or title tooltips?
- One h1, headings in order, every status and trend written in words, 44px targets, visible focus, labeled inputs?
- No personal data in URLs, logs, or localStorage? SSO and authorization checked on every request?
Fix what you find, then run `npx ucsd-decorator-kit verify` and report the findings. Don't run --accept.
Student success · College advising
Advisor caseload
For: college academic advisors. Data: student
records (FERPA), appointments, holds, early alerts.
Template: blank-slate.html
Filter bar: term and college
Four key numbers: caseload, appointments today, holds, early alerts
Today's appointments table and an early-alert status list
Build an advisor caseload dashboard for [college] advisors in [advising.html], from blank-slate.html, with css/app-patterns.css. Canvas, inside div.app-shell:
1. h4.app-view-title "Advisor Caseload · [College]".
2. form.app-filterbar: Term and College selects, Apply.
3. Four div.styled.app-stat key numbers: Students assigned, Appointments today, Registration holds (with an .app-trend), New early alerts.
4. A .row: .col-md-7 has a table.styled-dark.app-table "Today's appointments" (Time, Student, Reason; each student name links to a detail view). .col-md-5 has a div.app-panel "Early alerts" with ul.app-status-list (status in words).
FERPA data: require campus SSO, and return only students assigned to the signed-in advisor, checked server-side on every request. No student IDs or names in URLs, logs, or browser storage. Show preferred names. Log access to student records for audit. Data comes from [endpoint], loaded in js/advising.js.
Academic affairs · Department scheduling
Course enrollment and waitlists
For: department schedulers and undergraduate coordinators.
Data: section capacity, enrollment, and waitlists, all aggregate.
Template: two-column.html
Quarter switcher (segmented control)
Data bars: fill rate by course
Waitlist table, sorted by pressure, with an export action
Live preview
Enrollment · Cognitive Science
Seats filled
COGS 1100% (full)
COGS 14A92%
COGS 10881%
COGS 18046%
Largest waitlists
Course
Waitlist
Cap
COGS 1
84
400
COGS 14A
31
250
COGS 108
12
300
Prompt
Build a course enrollment dashboard for the [department] in [enrollment.html], from two-column.html, with css/app-patterns.css. Add it to the drawer, the navbar, and the side nav. Canvas, inside div.app-shell:
1. div.app-view-head: h4.app-view-title "Enrollment · [Department]" and a .btn-group.app-segmented quarter switcher [Fall, Winter, Spring].
2. A .row: .col-md-6 has a div.app-panel "Seats filled" with ul.app-bars per course (a full course gets .app-bar-attn, and the value text says "100% (full)"). .col-md-6 has a table.styled-dark.app-table "Largest waitlists" (Course, Waitlist, Cap), sorted by waitlist, then an .app-savebar with an "Export CSV" button.
Aggregate data only, with no student-level rows. Load it from [endpoint] per quarter in js/enrollment.js, and announce quarter changes in an aria-live region.
Research · Department research administration
Proposals and awards
For: department research administrators and PIs.
Data: proposal pipeline, sponsor deadlines, award spending.
Awards needing closeout or no-cost extension decisions.
Prompt
Build a research administration dashboard for [department] in [research.html], from blank-slate.html, with css/app-patterns.css. Canvas, inside div.app-shell:
1. h4.app-view-title "Research Administration · [Department]".
2. A .row: .col-md-6 has a div.app-panel "Proposal pipeline" with ul.app-bars per stage [Drafting, Dept. review, At OCGA, Submitted] showing counts. .col-md-6 has a div.app-panel "Next 30 days" with ol.app-timeline of sponsor deadlines (data-urgent within 7 days).
3. Bootstrap tabs (.app-tabs): "Active awards" and "Ending in 90 days" (with a count badge). Each is a table.styled-dark.app-table (Award, Sponsor, Spent %, Ends). Explain over- or under-spending in words.
Budget data is confidential: SSO, show only awards where the user is PI or a department admin (checked server-side), no amounts in URLs or logs. Data from [endpoint], in js/research.js.
Housing, Dining & Hospitality
Residence operations
For: residential life and operations staff. Data:
occupancy by neighborhood, maintenance tickets, dining location status.
Template: blank-slate.html
Key numbers: beds filled, open work orders, move-in checklist
Occupancy data bars by college
Dining locations status list
Live preview
Residence Operations · Fall move-in
15,240Beds filled Up 310 today
87Open work orders
4 of 6Move-in tasks done
Occupancy by college
Revelle97%
Warren95%
Eighth86%
Seventh66% (check-ins open)
Dining locations
64 DegreesOpen
PinesLong line
Club MedClosed
Prompt
Build a residence operations dashboard in [housing.html], from blank-slate.html, with css/app-patterns.css. Canvas, inside div.app-shell:
1. h4.app-view-title "Residence Operations · [event]".
2. Three .col-sm-4 div.styled.app-stat: Beds filled (with an .app-trend), Open work orders, Move-in tasks done ("4 of 6").
3. A .row: .col-md-7 has a div.app-panel "Occupancy by college" with ul.app-bars for [Revelle … Eighth] (explain the highlighted row in its value text). .col-md-5 has a div.app-panel "Dining locations" with ul.app-status-list (Open / Long line / Closed).
Refresh every [5] minutes in js/housing.js and announce "Updated [time]" in an aria-live region, without moving focus. Aggregate data only — no resident names on this screen.
IT Services · Working example
Service status board
For: the service desk and anyone checking campus systems.
Data: public service status. This one works:
filter to issues, search by name, and the count updates for screen readers.
The script is js/status-board.js,
about 60 lines of plain JavaScript.
Template: blank-slate.html
Key numbers: operational, degraded, outages
Item bar: an All / Needs attention filter, search, and a live count
Status list with detail lines, plus an empty state
Live preview · try it
Campus Service Status
Updated 9:41 a.m.
9Operational
2Degraded
1Outage
12 services shown
Canvas LMS Operational
UCSD-PROTECTED Wi-Fi DegradedSlow connections in Geisel Library. Engineers are on site.
Email and Calendar Operational
Print stations OutageCard readers offline campus-wide. Next update 11 a.m.
VPN Operational
Single Sign-On Operational
Zoom Operational
Library catalog DegradedSearches may time out. The vendor is investigating.
TritonLink Operational
Campus phones Operational
Research storage Operational
Concur Operational
No services match. Clear the search or choose "All".
Prompt
Build a campus service status board in [status.html], from blank-slate.html, with css/app-patterns.css, following the working example in the Decorator Kit Developer Guide (js/status-board.js). Canvas, inside div#its-board.app-shell:
1. div.app-view-head: h4.app-view-title "Campus Service Status" and an "Updated [time]" span.app-muted.
2. Three .col-xs-4 div.styled.app-stat counts: Operational, Degraded, Outage.
3. div.btn-toolbar.app-toolbar: a .btn-group.app-segmented radio filter [All, Needs attention], a span.app-live-count with role="status", and a right-aligned search form (.sr-only label).
4. ul.app-status-list with one li per service, carrying data-service and data-status, a status badge, and an optional detail line. Then a hidden div.app-empty.
Render the full list in HTML so it works without JavaScript. In js/status-board.js, filter by toggling Bootstrap's .hidden class. Listen for filter changes with jQuery ($(board).on('change', ...)), because button.js fires them through jQuery. Search on input. Update the count text on every change. Load statuses from [status feed] on an interval.
Facilities management · Sustainability
Energy and work orders
For: facilities managers and sustainability staff.
Data: building energy use against targets, work orders by priority.
Template: blank-slate.html
Filter bar: date range
Key numbers with trends against last year
Energy use against target as data bars, and a work-order tab set
Live preview
Energy & Work Orders · September
18.2GWh used Down 4% from last year
71%From on-site generation
243Open work orders Up 12 this week
Energy use against monthly target (top buildings)
Jacobs Hall108% (over)
Geisel Library92%
Price Center79%
Prompt
Build an energy and work-order dashboard in [energy.html], from blank-slate.html, with css/app-patterns.css. Canvas, inside div.app-shell:
1. h4.app-view-title "Energy & Work Orders · [period]" and a form.app-filterbar with From/To dates.
2. Three .col-sm-4 div.styled.app-stat with .app-trend compared to last year: GWh used, % from on-site generation, Open work orders.
3. A div.app-panel "Energy use against monthly target" with ul.app-bars for the top [10] buildings. Cap the bar at app-w-100 and say "[n]% (over)" in the value text when a building is over target.
4. Bootstrap tabs (.app-tabs) for work orders by priority [Emergency, Urgent, Routine]. Each is a table.styled-dark.app-table.
If a real chart is needed, add a charting library under canvas-components/ with its README, and keep the data table as the accessible alternative. Data from [endpoint], in js/energy.js.
UC San Diego Library
Study space availability
For: students (public view) and library staff.
Data: room status, occupancy by floor, busy hours.
Build a study room availability page in [rooms.html], from blank-slate.html, with css/app-patterns.css. Canvas, inside div.app-shell:
1. div.app-view-head: h4.app-view-title "[Building] Study Rooms" and a .btn-group.app-segmented floor switcher.
2. A .row: .col-md-7 has ul.app-tiles with one li per room — the room name, a span.app-status in words ("Available", "In use until 3 p.m.", "Reserved at 2 p.m."), and for available rooms a "Book" link with .sr-only room context. .col-md-5 has a div.app-panel "Usually busy" with ul.app-bars by hour.
Students are anonymous on this page — show no booker names. "Book" goes to [booking system] and needs SSO there. Refresh statuses every [2] minutes in js/rooms.js and announce changes politely.
Human Resources · Department HR
New-hire onboarding tracker
For: department HR contacts and hiring managers.
Data: personnel records and onboarding task status.
Template: two-column.html
Side menu of new hires with progress counts
The selected hire's checklist progress
Upcoming start dates timeline (in the prompt; not shown in the preview)
Live preview
Alex Kim · Programmer Analyst · starts Oct 1
3 of 5 done60%
Offer letter signed (done)
Background check (done)
Active Directory account (done)
Cyber-security training (to do)
Equipment request (to do)
Prompt
Build a new-hire onboarding tracker in [onboarding.html], from two-column.html, with css/app-patterns.css. Add it to the drawer, the navbar, and the side nav. Canvas, inside div.app-shell, as a .row:
1. .col-sm-3: nav aria-label="New hires" > .list-group.app-sidemenu with a heading "Starting soon" and one link per hire with a "[done]/[total]" badge. The selected hire gets aria-current="page".
2. .col-sm-9: a div.app-panel titled "[name] · [title] · starts [date]", a one-row ul.app-bars "[n] of [total] done", and ul.app-checklist (data-done plus .sr-only "(done)" / "(to do)").
3. Below it, a div.app-panel "Start dates" with ol.app-timeline (data-urgent for starts within 7 days where tasks are still open).
Personnel data: SSO, show only hires in the user's department (checked server-side), no names or employee IDs in URLs, and audit-log every view. Data from [endpoint], in js/onboarding.js.