P
UI Design System Docs

Component Documentation

UI Design System · v1.0 · HTML reference with copy-paste examples

Buttons

Use .ui-btn with a variant modifier. Works on <button> and <a>.

Solid variants

<button class="ui-btn ui-btn--primary">Primary</button>
<button class="ui-btn ui-btn--secondary">Secondary</button>
<button class="ui-btn ui-btn--success">Success</button>
<button class="ui-btn ui-btn--warning">Warning</button>
<button class="ui-btn ui-btn--danger">Danger</button>

Outline variants

<button class="ui-btn ui-btn--outline-primary">Outline Primary</button>
<button class="ui-btn ui-btn--outline-secondary">Outline Secondary</button>
<button class="ui-btn ui-btn--outline-danger">Outline Danger</button>
<button class="ui-btn ui-btn--ghost">Ghost</button>

Sizes

<button class="ui-btn ui-btn--primary ui-btn--sm">Small</button>
<button class="ui-btn ui-btn--primary">Default</button>
<button class="ui-btn ui-btn--primary ui-btn--lg">Large</button>

States — disabled & loading

<!-- Disabled -->
<button class="ui-btn ui-btn--primary" disabled>Disabled</button>

<!-- Loading (hides text, shows spinner) -->
<button class="ui-btn ui-btn--primary is-loading">Saving…</button>

Button group

<div class="ui-btn-group">
  <button class="ui-btn ui-btn--outline-primary">Day</button>
  <button class="ui-btn ui-btn--primary">Week</button>
  <button class="ui-btn ui-btn--outline-primary">Month</button>
</div>

Badges

Inline status labels. Use .ui-badge with a colour and optional style modifier.

Soft (default)

Active Pending Overdue Info Primary Secondary
<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

Active Pending Inactive
<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

Primary Success Warning Danger
<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)

Admin Physician Read Only Billing
<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)

Scheduled downtime tonight at midnight.

<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 month
🏥

Open 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

▼ 3

Revenue

$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

Enter your legal name.
<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

Maximum 500 characters.
<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

Enter a valid email address.
<!-- 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, MichaelDr. PatelActive2025-11-20
Brown, SarahDr. KimPending2025-10-05
Chen, LindaDr. PatelActive2025-11-15
Diaz, CarlosDr. HassanInactive2024-06-12
Evans, PatriciaDr. KimActive2025-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

NameRoleStatus
Jane DoeAdminActive
Mark SmithPhysicianActive
Anna LeeNursePending
<!-- 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>