Badges
Inline status labels. Use .ui-badge with a colour and optional style modifier.
Soft (default)
<span class="ui-badge ui-badge--success">Active</span>
<span class="ui-badge ui-badge--warning">Pending</span>
<span class="ui-badge ui-badge--danger">Overdue</span>
<span class="ui-badge ui-badge--info">Info</span>
<span class="ui-badge ui-badge--primary">Primary</span>
<span class="ui-badge ui-badge--secondary">Secondary</span>
With status dot
<span class="ui-badge ui-badge--success ui-badge--dot">Active</span>
<span class="ui-badge ui-badge--warning ui-badge--dot">Pending</span>
<span class="ui-badge ui-badge--danger ui-badge--dot">Inactive</span>
Solid
<span class="ui-badge ui-badge--solid-primary">Primary</span>
<span class="ui-badge ui-badge--solid-success">Success</span>
<span class="ui-badge ui-badge--solid-warning">Warning</span>
<span class="ui-badge ui-badge--solid-danger">Danger</span>
Role & permission (Security module)
<span class="ui-badge ui-badge--role">Admin</span>
<span class="ui-badge ui-badge--permission">Read Only</span>
Alerts
Inline feedback messages. Add data-ui-alert-dismiss to the dismiss button for auto-close behaviour.
Standard variants
Success
Patient record saved successfully.
Warning
This action cannot be undone.
Error
Failed to connect to server.
Info
System maintenance Sunday 2–4 AM.
<div class="ui-alert ui-alert--success">
<span class="ui-alert__icon">✓</span>
<div class="ui-alert__body">
<p class="ui-alert__title">Success</p>
<p class="ui-alert__text">Patient record saved successfully.</p>
</div>
</div>
<!-- swap ui-alert--success for: ui-alert--warning | ui-alert--danger | ui-alert--info -->
Dismissible
Click × to dismiss this alert.
<div class="ui-alert ui-alert--info">
<span class="ui-alert__icon">ℹ</span>
<div class="ui-alert__body">
<p class="ui-alert__text">Message here.</p>
</div>
<button class="ui-alert__dismiss" data-ui-alert-dismiss aria-label="Dismiss">✕</button>
</div>
Banner (full-width, no radius)
<div class="ui-alert ui-alert--warning ui-alert--banner">
<span class="ui-alert__icon">⚠</span>
<div class="ui-alert__body">
<p class="ui-alert__text">Scheduled downtime tonight at midnight.</p>
</div>
</div>
Cards
Surface container for grouped content. Base class .ui-card; BEM elements __header, __body, __footer.
Base card
Card Title
Optional subtitle
Card body content goes here.
<div class="ui-card">
<div class="ui-card__header">
<div>
<h3 class="ui-card__title">Card Title</h3>
<p class="ui-card__subtitle">Optional subtitle</p>
</div>
<div class="ui-card__actions">
<button class="ui-btn ui-btn--ghost ui-btn--sm">Action</button>
</div>
</div>
<div class="ui-card__body">
<p>Content here.</p>
</div>
<div class="ui-card__footer">
<span>Footer note</span>
<span>Updated just now</span>
</div>
</div>
Statistics card
Total Patients
1,842
▲ 12% this monthOpen Tasks
47
▼ 3 since yesterday<div class="ui-card ui-card--stat">
<div class="ui-card__body">
<p class="ui-card__stat-label">Total Patients</p>
<p class="ui-card__stat-value">1,842</p>
<span class="ui-card__stat-change ui-card__stat-change--up">▲ 12% this month</span>
<div class="ui-card__stat-icon"><!-- icon --></div>
</div>
</div>
<!-- Change direction: ui-card__stat-change--up | --down | --flat -->
Statistics grid (responsive 4-column)
Patients
1,842
▲ 12%Tasks
47
▼ 3Revenue
$94K
▲ 8%Staff
23
— No change<div class="ui-stats-grid">
<div class="ui-card ui-card--stat">...</div>
<div class="ui-card ui-card--stat">...</div>
<div class="ui-card ui-card--stat">...</div>
<div class="ui-card ui-card--stat">...</div>
</div>
<!-- Grid auto-fits: 200px min per column, fills available width -->
Summary card (coloured left border)
Highlighted information with a primary-colour left border.
<div class="ui-card ui-card--summary">
<div class="ui-card__body">
<p>Content here.</p>
</div>
</div>
Action card (hover lift)
📋
New Report
<div class="ui-card ui-card--action">
<div class="ui-card__body">
<!-- clickable card content -->
</div>
</div>
Forms
Add data-ui-validate to the form element for automatic browser-native validation with styled error messages.
Text input
<div class="ui-form-group">
<label class="ui-label ui-label--required" for="name">Full Name</label>
<input type="text" id="name" class="ui-input" placeholder="Jane Doe" required>
<span class="ui-form-help">Enter your legal name.</span>
<span class="ui-form-error"></span>
</div>
<!-- Types: text | email | tel | number | date | password -->
<!-- States: add .is-valid or .is-invalid to the input -->
Select
<div class="ui-form-group">
<label class="ui-label" for="role">Role</label>
<select id="role" class="ui-select">
<option value="">Select a role…</option>
<option>Administrator</option>
<option>Physician</option>
</select>
</div>
Textarea
<div class="ui-form-group">
<label class="ui-label" for="notes">Notes</label>
<textarea id="notes" class="ui-textarea" placeholder="Optional notes…"></textarea>
<span class="ui-form-help">Maximum 500 characters.</span>
</div>
Checkbox & radio
<!-- Checkbox -->
<label class="ui-check">
<input type="checkbox" class="ui-check__input" name="active">
<span>Account is active</span>
</label>
<!-- Radio -->
<label class="ui-check">
<input type="radio" class="ui-check__input" name="option" value="a">
<span>Option A</span>
</label>
Input group (prefix / suffix)
<!-- Prefix -->
<div class="ui-input-group">
<span class="ui-input-group__prefix">$</span>
<input type="number" class="ui-input" placeholder="0.00">
</div>
<!-- Suffix -->
<div class="ui-input-group">
<input type="text" class="ui-input" placeholder="Search…">
<span class="ui-input-group__suffix">⌕</span>
</div>
Validation states
<!-- Valid -->
<input class="ui-input is-valid" type="email" value="jane@clinic.ca">
<!-- Invalid -->
<input class="ui-input is-invalid" type="email" value="not-an-email">
<span class="ui-form-error is-visible">Enter a valid email address.</span>
Full form with auto-validation
<form data-ui-validate>
<div class="ui-form-group">
<label class="ui-label ui-label--required" for="email">Email</label>
<input type="email" id="email" class="ui-input" required placeholder="jane@clinic.ca">
<span class="ui-form-error"></span>
</div>
<div class="ui-d-flex ui-gap-sm ui-mt-md">
<button type="submit" class="ui-btn ui-btn--primary">Save</button>
<button type="reset" class="ui-btn ui-btn--outline-secondary">Cancel</button>
</div>
</form>
<!-- data-ui-validate: auto-init by ui-forms.js on DOMContentLoaded -->
<!-- Fires: ui:form:submit, ui:form:error -->
Tables
Wrap a standard HTML table with data-ui-table. DataTables auto-initialises search, sort, and pagination. Requires ui-tables.js.
Standard data table
| Patient | Provider | Status | Last Visit |
|---|---|---|---|
| Adams, Michael | Dr. Patel | Active | 2025-11-20 |
| Brown, Sarah | Dr. Kim | Pending | 2025-10-05 |
| Chen, Linda | Dr. Patel | Active | 2025-11-15 |
| Diaz, Carlos | Dr. Hassan | Inactive | 2024-06-12 |
| Evans, Patricia | Dr. Kim | Active | 2025-11-01 |
<div class="ui-table-wrapper">
<table data-ui-table
data-ui-search="true"
data-ui-page-size="25"
class="table table-hover w-100"
id="my-table">
<thead>
<tr>
<th>Patient</th>
<th>Provider</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Adams, Michael</td>
<td>Dr. Patel</td>
<td><span class="ui-badge ui-badge--success ui-badge--dot">Active</span></td>
</tr>
</tbody>
</table>
</div>
<!-- data-ui-table attributes:
data-ui-search="true" — enable search box
data-ui-page-size="25" — rows per page (default 25)
data-ui-export="true" — export buttons (requires buttons plugin)
-->
<!-- Fires: ui:table:row-click, ui:table:export -->
Compact style
| Name | Role | Status |
|---|---|---|
| Jane Doe | Admin | Active |
| Mark Smith | Physician | Active |
| Anna Lee | Nurse | Pending |
<!-- Add .ui-table--compact to the wrapper for tighter rows -->
<div class="ui-table-wrapper ui-table--compact">
<table data-ui-table class="table table-hover w-100">
...
</table>
</div>
Modals
Use data-ui-modal-open="id" to open and data-ui-modal-close to close. Managed by ui-core.js. Press Escape to close.
Trigger buttons
<!-- Trigger -->
<button class="ui-btn ui-btn--primary" data-ui-modal-open="my-modal">Open</button>
<!-- Modal overlay (place before </body>) -->
<div class="ui-modal-overlay" id="my-modal"
aria-hidden="true" aria-modal="true" role="dialog"
aria-labelledby="my-modal-title">
<div class="ui-modal ui-modal--md"> <!-- sm | md | lg | xl | fullscreen -->
<div class="ui-modal__header">
<h2 class="ui-modal__title" id="my-modal-title">Edit Record</h2>
<button class="ui-modal__close" data-ui-modal-close aria-label="Close">✕</button>
</div>
<div class="ui-modal__body">
<!-- content -->
</div>
<div class="ui-modal__footer">
<button class="ui-btn ui-btn--outline-secondary" data-ui-modal-close>Cancel</button>
<button class="ui-btn ui-btn--primary">Save Changes</button>
</div>
</div>
</div>
<!-- Footer aligned left + right: add .ui-modal__footer--between -->
Toast Notifications
Programmatic API via window.UI.notify(). Requires ui-notifications.js.
Trigger examples
<!-- Simple -->
UI.notify('Patient record saved.', 'success');
<!-- With options -->
UI.notify('Message here.', 'warning', {
duration: 4000, // ms — 0 = sticky until dismissed
position: 'bottom-right', // top-right | bottom-right | bottom-left | top-center
dismissable: true
});
<!-- Types: 'success' | 'warning' | 'danger' | 'info' -->
<!-- Fires: ui:notification:dismissed -->
Activity Feed
Chronological event list. Render server-side; no JavaScript required.
Feed inside a card
Activity Feed
Recent system events
-
JD
Jane Doe updated patient record #4821.
2 minutes ago
-
MS
Mark Smith approved leave request.
14 minutes ago
-
SY
System generated monthly billing report.
1 hour ago
<ul class="ui-feed">
<li class="ui-feed__item">
<div class="ui-feed__avatar">JD</div> <!-- initials or icon -->
<div class="ui-feed__body">
<p class="ui-feed__description">
<strong>Jane Doe</strong> updated patient record #4821.
</p>
<p class="ui-feed__time">2 minutes ago</p>
</div>
</li>
<li class="ui-feed__item">
...
</li>
</ul>