Frontend Design Kit Style Guide
Style guide for the frontend design kit.
Purpose
This guide documents the visual and composition patterns already used by the HIS frontend design-kit layer and the following reference modules:
apps/ever/ui/web/src/modules/medical-record/future-order-checked-in/apps/ever/ui/web/src/modules/medical-record/future-order-wait-check-in/apps/ever/ui/web/src/modules/medical-record/medical-record-table/apps/ever/ui/web/src/modules/medical-record/vital-sign/apps/ever/ui/web/src/modules/list-patient/visit/DialogAppointment.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogCreateVisit.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogDocument.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogNhsoAgent.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogNhsoWebService.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogViewHistory.tsxapps/ever/ui/web/src/modules/screening-patient/dialog-screening/
The goal is to keep new UI work visually consistent with the shared wrapper components under:
src/common/components/mui/src/common/components/custom/
Core Principle
Build UI with the shared design-kit wrappers first, and only drop to raw MUI when the design-kit does not already provide the behavior or styling you need.
Prefer:
@components/mui/button@components/mui/typography@components/mui/text-field@components/mui/select@components/mui/chip@components/custom/dialog-form@components/custom/dialog-info-header@components/custom/table
Design Language Summary
The referenced screens consistently use the following visual language:
- Rounded surfaces: primary containers and dialogs use
8pxor16pxradii. - Soft neutral framing: headers use light gray backgrounds, bordered inputs use soft gray outlines, and tables use subtle dividers.
- Compact healthcare density: data-heavy screens keep row height tight, but preserve readable padding.
- Strong sectioning: dialogs are broken into clear blocks using dividers, cards, boxed sections, and spacing.
- Single accent color: primary actions and interactive emphasis use the green primary tone.
- Semantic status colors: chips, warnings, and special states should use the shared semantic templates rather than ad hoc colors.
Foundation Components
Dialogs
DialogForm
Use DialogForm as the default modal shell for standard dialogs.
Observed style characteristics:
- dialog paper uses
border-radius: 16px - title bar uses a light gray background
- title content is padded with approximately
18px 24px - footer actions typically use
24pxpadding - content commonly uses
DialogContentinside the wrapper
Use DialogForm for:
- visit registration dialogs
- coverage/history dialogs
- document preview dialogs
- NHSO dialogs
- table-based modal flows
Preferred composition:
DialogForm- patient header or title section
- divider
- main content blocks
- custom footer with action buttons
DialogWithInfo
Use DialogWithInfo for large workflows that need a patient information panel and configurable content area, such as:
- screening
- future order workflows
- multi-step clinical dialogs
Observed behavior:
- wraps
DialogForm - adds a patient information header/panel
- defaults inner content padding to
24px - supports top/left/right layout modes
- is used for high-context clinical workflows
Important note:
DialogWithInfois marked deprecated in code and recommendsDialogMaster- for legacy-consistent screens, follow the current visual treatment
- for new large workflows, verify whether
DialogMasteris now the preferred shell before introducing anotherDialogWithInfo
Dialog Layout Rules
Across the referenced dialogs, the common structure is:
- Header: title and close action handled by
DialogForm - Patient context:
HeaderPatientInformationorDialogInfoPatient - Divider: placed immediately after patient context
- Body: section blocks with
24pxinternal padding or card-like boxed sections - Footer: bottom action row with
24pxpadding and a top border or divider
Recommended footer patterns:
- Single dismiss action: right-aligned outlined button
- Cancel + confirm: outlined secondary action, contained primary action
- Destructive + standard actions: destructive action left, cancel/save group right
- Long forms: keep footer fixed within dialog shell rather than floating inside content
Spacing System
The referenced modules repeatedly use these spacing values:
4pxfor tight inline gaps8pxfor compact internal spacing10pxto12pxfor small action separation16pxfor section inset and first-column table padding24pxfor dialog padding, card padding, and footer padding30pxor32pxfor larger section breaks
Recommended usage:
- Dialog shell content:
24px - Section-to-section gap inside dialog:
24pxto32px - Inline button gap:
8pxto10px - Compact field group gap:
8pxto16px - Table first column padding:
16px
Border Radius
Use the existing radius hierarchy:
- 16px
- dialog shells
- tab tops
- large cards/boxed sections
- 8px
- buttons
- text inputs
- selects
- compact cards
- table wrappers
- vital sign cells
- 4px
- standard chips
Typography
Always use the shared Typography wrapper when possible.
Common altColor values seen in the referenced modules:
textBlackMaintextBlackDarktextBlackLighttextBlackDisableprimaryMain
Typical roles:
- Dialog title:
variant="h8" - Section title:
variant="h6",h8, orh9 - Field label / table header:
variant="inputLabel" - Regular content:
body1,body2, or default text - Dense tab label:
h9
Rules:
- use uppercase sparingly for compact metadata headings and table labels
- prefer wrapper-driven color tokens instead of hardcoded hex values
- if text is translated, use the
i18nprop or surrounding translation pattern consistently
Buttons
Use the shared Button wrapper.
Observed styling:
- default button radius is
8px roundedcreates pill-style actions for emphasis in some flows- loading state is built in
- contained buttons are the primary commit action
- outlined buttons are the default secondary action
Recommended usage:
- Primary action:
variant="contained" - Secondary action:
variant="outlined" - Neutral dismiss: outlined
- Add row / add item: outlined or contained with
startIcon - Dialog footer: keep no more than one dominant contained action
Form Grid Layout
Use MUI v7 Grid2 (import { Grid } from '@mui/material') with size={{ xs: 12, sm: N }} responsive breakpoints. Do not use the old Grid1 pattern (item xs={N} sm={N}) or mix item with size.
Never stretch short inputs to full width
When a field’s expected value is short (a few characters or a short list), it must not fill the entire dialog width. Expanding a 2-character dropdown to 100% width wastes space and makes the form harder to scan clinically.
Examples of short inputs that must share a row:
| Field | Max value length | Recommended column span |
|---|---|---|
| กลุ่มเลือด (A / B / AB / O) | 2–3 chars | sm={2} (2 of 12) |
| Rh (+/-) | display text | sm={2} |
| Unit Number | short code | sm={2} |
| BP systolic / diastolic | 3 digits each | sm={2} total (nested 5/2/5) |
| PULSE | 3 digits | sm={2} |
| TEMP (ปกติ / สูง / ต่ำ) | 3 options | sm={2} |
| ครั้งที่บริจาค | small number | sm={2} |
| น.น. (weight) | kg value | sm={2} |
Correct MUI v7 Grid2 syntax:
<Grid container spacing={2}>
{/* Short fields — 6 per row at sm+ */}
<Grid size={{ xs: 12, sm: 2 }}>
<Autocomplete label="กลุ่มเลือด" ... />
</Grid>
<Grid size={{ xs: 12, sm: 2 }}>
<Autocomplete label="RH" ... />
</Grid>
{/* Medium fields — 2 per row at sm+ */}
<Grid size={{ xs: 12, sm: 6 }}>
<TextField label="COPPER SULFATE" ... />
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<TextField label="ปริมาณเลือด" ... />
</Grid>
</Grid>
Wrong (do not use):
// Wrong: old Grid1 API — does not work in MUI v7
<Grid item xs={12} sm={2}>...</Grid>
// Wrong: size={12} overrides responsive breakpoints, forces full width
<Grid item size={12} sm={2}>...</Grid>
// Wrong: stretching short input to full width
<Grid size={{ xs: 12 }}>
<Autocomplete label="กลุ่มเลือด" ... /> {/* A/B/AB/O — does not need 100% width */}
</Grid>
Date + time always paired on the same row
Date fields and their paired time fields must always share a row:
<Grid size={{ xs: 12, sm: 2 }}>
<InputDatePicker label="วันที่บริจาค" ... />
</Grid>
<Grid size={{ xs: 12, sm: 2 }}>
<InputTimePicker label="เวลาให้เลือด" ... />
</Grid>
Table action columns
Use isSticky: true on the ITableColumn definition for action columns so they remain fixed to the right side when the table scrolls horizontally. The DynamicTable RowRenderer and HeaderCellRenderer will automatically use ActionCell (sticky, right: 0, z-index 1, shadow) when isSticky is set.
Text Inputs
Use the shared TextField wrapper.
Observed wrapper behavior:
- label font size
12px - label weight
700 - input border radius
8px - standard input padding around
10px 12px - supports read-only and number restrictions
- supports alternate disabled treatment via
altDisabledColor
Rules:
- labels should sit above the field, not inside as the primary identifier
- keep multiline note fields visually aligned with standard form fields
- for dense workflows, stay consistent with existing label-weight and border styling
Select Inputs
Use the shared Select wrapper.
Observed wrapper behavior:
8pxborder radius24pxtop margin from label to control- outlined border with hover/focus state switching to primary color
- label matches text-field label treatment
- supports placeholders, chips rendering, multi-select, clear action, and disabled alt styling
Rules:
- use
fieldNameRenderandfieldValueconsistently - when options are complex, provide a display string such as
code - name - use chip rendering only when selection state benefits from visual tokenization
Chips and Status Badges
Use the shared Chip wrapper and template values from the design-kit.
Observed styling:
- default chip radius
4px - bold label text
- semantic text/background/border derived from template
Common use cases in the referenced screens:
- status pills in future orders
- compact count indicators
- ESI or priority-style selection summaries
- selected values inside multi-select controls
Rules:
- use template-based semantic colors instead of hardcoded badge colors
- keep chips concise
- use rounded count chips only for small numeric summaries
Tabs
Use existing styled tabs where available, such as CustomTabsMain and CustomTabMain.
Observed style characteristics:
- tab container may sit on a gray background strip
- inactive tabs use soft gray backgrounds
- selected tabs switch to white with stronger weight
- top corners are rounded at
16px - indicator can be hidden when the design relies on surface change instead
Tables
Use @components/custom/table for standard tables and keep custom table implementations visually aligned with it.
Shared table treatment:
- sticky header support
- white header background
- header bottom border
- header padding around
16px 8px, with first column often16px - body rows use alternating striping
- hover state uses a pale green tint
- compact body row height around
30px - outer border and radius are optional depending on context
Table design rules:
- use
Typography variant="inputLabel"for header labels - keep first column padding wider than others
- prefer alternating row shading for scanability
- support no-data and loading states inside the table body
- use expand rows only when secondary detail truly belongs to the record
- keep row actions compact and aligned to the right
Section Cards and Boxed Panels
The reference dialogs often wrap major form sections in elevated boxes.
Observed pattern:
- white background
16pxradius24pxpadding- subtle gray shadow
- section heading aligned left
- top-right action cluster for add/manage actions
Use this pattern for:
- treatment rights section
- large grouped form blocks
- read-mode detail panels
- multi-field information groups inside a larger dialog
Patient Information Blocks
Patient context is always visually prominent and appears near the top of the dialog.
Patterns seen:
HeaderPatientInformationdirectly beneath the dialog titleDialogInfoPatientas a richer info panel for workflow dialogs- a divider immediately below the patient summary
Rules:
- do not bury patient identity below other content
- keep patient context visible before the first editable clinical or administrative section
- use a divider to clearly separate identity from task content
Forms in Read Mode vs Edit Mode
The reference modules consistently distinguish between read mode and edit mode.
Read mode
- present grouped information in boxed or card sections
- use label/value pairs
- reduce input chrome
- preserve section ordering from the edit view
Edit mode
- use wrapper controls
- maintain the same section titles and layout structure
- allow add/remove actions near the section title area
- keep action density manageable with clear primary/secondary emphasis
Vital Sign Pattern
The vital-sign UI establishes a compact clinical measurement pattern.
Observed style characteristics:
- individual vital sign boxes use
8pxradius - focused state changes background to primary light and border to primary main
- focused state also changes typography color to primary main
- read-mode panels use soft gray backgrounds and compact internal padding
Rules:
- keep vital measurement widgets dense but clearly focusable
- use visual state change on focus rather than heavy decoration at rest
- group clinically related values tightly
- preserve consistent box height across comparable measurements
Loading and Empty States
Use shared wrappers where available:
LoadingContentNoDataContent
Rules:
- loading states should occupy the content area they replace
- in dialogs, center major loaders when content is not yet available
- in tables, render loading and empty states inside the table body rather than outside the table shell
Recommended Composition Patterns
Standard Administrative Dialog
Use for:
- view history
- document display
- NHSO check dialogs
Structure:
DialogForm- patient header
- divider
- one or more boxed sections or content blocks
- footer with outlined and contained actions
Workflow Dialog With Patient Context
Use for:
- screening
- future order handling
- large nurse/doctor task flows
Structure:
DialogWithInfoor current approved successor- patient info panel enabled
- padded scrollable content column
- persistent footer actions
Data-Dense Table Screen
Use for:
- medical record worklists
- history tables
- waiting/check-in lists
Structure:
- filter and action bar
- shared table wrapper
- compact row actions
- optional right-side detail or popper actions
- pagination below or integrated with the layout
Do and Don’t
Do
- use design-kit wrappers first
- keep dialogs rounded and sectioned
- use
24pxas the default dialog and section padding anchor - use semantic chip templates
- preserve patient context at the top of workflow dialogs
- align table headers and body cells to the established padding rhythm
- use read mode and edit mode as visual siblings
Don’t
- build new dialogs directly on raw MUI without checking
DialogFormandDialogWithInfo - hardcode status colors when a chip template exists
- mix random border radii on the same screen
- overuse contained buttons in one action cluster
- use inconsistent field labeling patterns
- create bespoke table styling that breaks the established hover, stripe, and header treatment
Implementation Checklist For New Screens
Before merging a new screen or dialog, check:
- Is there a shared design-kit wrapper for every major primitive used?
- Does the dialog use
16pxshell rounding and24pxfooter/content rhythm? - Are labels using the same visual weight as existing fields?
- Are table rows, headers, hover, and striping consistent with the shared table?
- Are semantic statuses represented with shared chip templates?
- Is patient context placed at the top when the workflow is patient-specific?
- Does the screen look visually compatible with
DialogCreateVisit,DialogViewHistory,DialogScreening, and the medical record modules?
Reference Files
Shared wrappers
apps/ever/ui/web/src/common/components/custom/dialog-form/DialogForm.tsxapps/ever/ui/web/src/common/components/custom/dialog-form/style.tsapps/ever/ui/web/src/common/components/custom/dialog-info-header/DialogWithInfo.tsxapps/ever/ui/web/src/common/components/custom/table/Table.tsxapps/ever/ui/web/src/common/components/custom/table/style.tsapps/ever/ui/web/src/common/components/mui/button/Button.tsxapps/ever/ui/web/src/common/components/mui/button/style.tsapps/ever/ui/web/src/common/components/mui/text-field/TextField.tsxapps/ever/ui/web/src/common/components/mui/text-field/style.tsapps/ever/ui/web/src/common/components/mui/select/Select.tsxapps/ever/ui/web/src/common/components/mui/select/styles.tsapps/ever/ui/web/src/common/components/mui/typography/Typography.tsxapps/ever/ui/web/src/common/components/mui/chip/Chip.tsxapps/ever/ui/web/src/common/components/mui/chip/style.ts
Reference feature modules
apps/ever/ui/web/src/modules/list-patient/visit/DialogCreateVisit.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogAppointment.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogDocument.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogNhsoAgent.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogNhsoWebService.tsxapps/ever/ui/web/src/modules/list-patient/visit/DialogViewHistory.tsxapps/ever/ui/web/src/modules/medical-record/future-order-wait-check-in/FutureOrder.tsxapps/ever/ui/web/src/modules/medical-record/future-order-checked-in/FutureOrderCheckedIn.tsxapps/ever/ui/web/src/modules/medical-record/medical-record-table/MedicalRecordTable.tsxapps/ever/ui/web/src/modules/medical-record/vital-sign/VitalSign.tsxapps/ever/ui/web/src/modules/medical-record/vital-sign/style.tsapps/ever/ui/web/src/modules/screening-patient/dialog-screening/DialogScreening.tsx
Scope Note
This guide is intentionally grounded in the current codebase. When the shared design-kit evolves, update this document to reflect the wrappers and patterns that are actually in production use.