Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

03 — Component Library (Shared)

Every reusable client component shared across modules. Module docs 07_Component_Library.md list module-specific components and reference these by name. Flutter mapping assumes Material 3 (flutter/material, Material3 ThemeData).


A. Feedback & states

AppSkeleton

  • Purpose: loading placeholder for lists/cards/text.
  • Props: variant (text|circle|rect|list|card), width, height, lines, radius.
  • States: shimmer loop (m-slow), reduced-motion = static tint.
  • Tokens: surfaceVariant fill, e-0. Flutter: custom Skeleton widget or shimmer package wrapper (prefer custom to avoid dep).

AppEmptyState

  • Purpose: empty/zero-result content.
  • Props: icon, title, message, actionLabel, onAction, compact.
  • States: default; compact (inline list header).
  • A11y: container Semantics(label: title + message).
  • Tokens: displaySmall title, bodyMedium onSurfaceVariant. Flutter: Column + Icon + Text + FilledButton.tonal.

AppErrorState

  • Purpose: full-screen or inline fetch failure.
  • Props: code (error code from envelope), message, onRetry, details?, compact.
  • Rules: never expose stack/server internals; 500 → generic text + requestId hint.
  • Tokens: error icon, titleLarge, bodyMedium. Flutter: ErrorWidget-free custom widget.

AppOfflineBanner

  • Purpose: top banner when connectivity lost.
  • Props: visible, text (i18n offline.banner), onRetry.
  • Behaviour: auto-dismiss on connectivity restore; sticky at top, e-1.
  • Tokens: tertiaryContainer background. Flutter: MaterialBanner or custom AnimatedContainer.

AppSnackbar / AppToast

  • Purpose: transient feedback (success, error, info, undo).
  • Props: type, message, actionLabel?, onAction?, duration.
  • Rules: one snackbar at a time (queue), error type persists ≥ 4 s, success < 3 s.
  • Tokens: inverse surface, error/success icon accents. Flutter: ScaffoldMessenger wrapper.

AppBanner

  • Purpose: persistent inline message (e.g., "results published", "pending KYC docs").
  • Props: severity (info|success|warning|error), title, body?, dismissible.
  • Tokens: *Container role colors. Flutter: MaterialBanner.

B. Inputs

AppTextField

  • Props: label, hint, placeholder, keyboardType, textInputAction, formatters, validator, maxLength, prefix/suffixIcon, obscure, autofillHints, errorText, helperText, enabled, autofocus.
  • States: empty, filled, focused, error, disabled, read-only, loading (suffix spinner).
  • Validation: validator run on submit + on change after first error; error clears on edit.
  • A11y: label + Semantics(error) on error; error announced.
  • Tokens: surfaceVariant fill, outline border, error on error, focus primary.
  • Flutter: TextField/TextFormField with InputDecoration, InputFormatters.

AppDropdown (single select)

  • Props: label, items[{value,label}], value, onChanged, searchable?, loading?, emptyText, errorText, disabled.
  • Behaviour: opens AppBottomSheet picker or menu; selected value shown in field.
  • A11y: role "combobox", Semantics on options.
  • Flutter: custom field + showModalBottomSheet, or DropdownButtonFormField for ≤ 8 items.

AppSearchBar

  • Props: hint, debounceMs (default 300), onQuery, autofocus, suffix (clear), trailing (filter chips button).
  • Behaviour: debounced server search; clear restores list; stays on screen during search.
  • A11y: label, results announced (liveRegion).
  • Flutter: SearchBar (M3) with controller + debounce Timer.

AppChips (filter/tag/input)

  • Props: label, selected, onToggle, avatar?, onDelete? (input chips).
  • Flutter: FilterChip/InputChip/ActionChip.

AppDatePicker / AppTimePicker

  • Props: label, value, min/maxDate, onChanged, errorText.
  • Behaviour: opens M3 date/time picker dialog; locale-aware formatting; m-base transition.
  • Flutter: showDatePicker/showTimePicker wrappers; MaterialLocalizations.

AppSwitch / AppCheckbox / AppRadio

  • Standard M3 controls; props: label, value, onChanged, disabled, subtitle?.
  • A11y: label semantics, Semantics(toggled:)/checked:.
  • Flutter: Switch, Checkbox, Radio with ListTile wrappers.

AppSlider

  • Props: label, min/max/divisions, value, onChanged, valueLabel.
  • Flutter: Slider + SliderTheme.

C. Display

AppCard

  • Props: title?, subtitle?, trailing?, leading?, onTap?, elevation (e-0/e-1), padding, child.
  • Variants: flat (e-0), outlined (outlineVariant), tonal (primaryContainer).
  • A11y: whole-card tap = one Semantics(button:); inner controls excluded from card tap.
  • Flutter: Card/Card.filled with InkWell.

AppListTile

  • Props: leading, title, subtitle, trailing, onTap, dense?, selected?, badge?, menu? (trailing overflow menu).
  • Height ≥ 56; dense ≥ 48. Flutter: ListTile with custom MenuAnchor.

AppAvatar

  • Props: name, photoUrl?, size (24/32/40/48/64), presence?, onTap.
  • Fallback: initials from name on primaryContainer. Flutter: CircleAvatar + CachedNetworkImage-style cache.

AppBadge

  • Props: text, color (role), icon?, outlined?. Flutter: Badge/custom Container.

AppProgress

  • LinearProgressIndicator (paged loads) / CircularProgressIndicator (buttons, refresh).
  • Tokens: primary. Reduced-motion: determinate only.

AppTabs

  • Props: tabs[{label, icon?, badge?}], controller, scrollable?, onChanged.
  • Flutter: TabBar + TabBarView (keep-alive lists).

AppCharts

  • Purpose: KPI visualization (dashboard, reports, fees).
  • Props: type (bar|line|donut|gauge), series, labels, emptyText, height.
  • Rules: show values in tooltips + data labels; a11y: provide Semantics summary text; provide tabular fallback when charts not meaningful.
  • Flutter: fl_chart (recommended, already industry standard; verify license) — wrap in own AppChart widget so the lib is swappable.

AppAvatarStack, AppStatTile, AppInfoRow

  • StatTile: label, value, delta?, trend? for dashboards.
  • InfoRow: label, value, icon? for detail screens.

D. Navigation & actions

AppFAB

  • Props: icon, label? (extended), onPressed, heroTag (unique per screen!).
  • Rules: one FAB per screen; hidden on scroll-down, shown on scroll-up (list screens).
  • Flutter: FloatingActionButton/FloatingActionButton.extended; scroll listener.

AppButton (M3)

  • Variants: filled (primary CTA), filledTonal (secondary), outlined (tertiary), text (inline), icon (icon button w/ tooltip).
  • Props: label, icon?, loading? (spinner replaces icon), enabled, destructive? (error colors), fullWidth?, semanticLabel.
  • Height 40/48; touch target ≥ 48.
  • Flutter: FilledButton, FilledButton.tonal, OutlinedButton, TextButton, IconButton with Tooltip.

AppDialog

  • Props: title, content, actions, dismissible (barrier), destructiveAction?.
  • Behaviour: barrier tap = cancel unless dismissible=false; ESC/back closes; focus moves into dialog; m-base scale+fade.
  • Flutter: showDialog + AlertDialog; FocusScope.

AppBottomSheet

  • Props: title, draggable (drag handle), showDragHandle, children, isDismissible, height (half/full).
  • Rules: used for pickers, actions, filters; returns value via Navigator.pop(result).
  • Flutter: showModalBottomSheet with DragHandle (M3).

AppMenu (context menu)

  • Props: items[{label, icon?, destructive?, onTap}], semanticLabel.
  • Behaviour: long-press / trailing overflow opens MenuAnchor; ESC closes; focus ring.
  • Flutter: MenuAnchor + MenuItemButton.

AppTabBarTop + AppNavigationBar + AppNavigationDrawer + AppNavigationRail

  • AppNavigationBar: bottom nav for phones (3–5 destinations, AppDestinations list).
  • AppNavigationDrawer: full menu (all sections) for large screens; slide-in on phone via hamburger.
  • AppNavigationRail: tablet/desktop ≥ 840 dp.
  • Rules: selected destination = primary indicator (pill); badges show unread counts.
  • Flutter: NavigationBar, NavigationDrawer, NavigationRail.

E. Content & media

AppSectionHeader

  • Props: title, actionLabel?, onAction?, subtitle?. Section gaps 24 top.
  • Flutter: Row with titleMedium + TextButton.

AppAttachmentTile

  • Props: name, size, type, url, onPreview, onDownload?, uploading?, onRemove?.
  • Preview: PDF/image viewers; files open in external viewer via share sheet.
  • Flutter: ListTile + file-type icon map.

AppMarkdownViewer

  • Purpose: homework descriptions, announcements, notices.
  • Props: data, compact?, onLinkTap.
  • Flutter: flutter_markdown (wrap; sanitize links).

AppStepper

  • Purpose: multi-step flows (enrollment, admission, bulk import wizard).
  • Props: steps[{title, state}], currentIndex, onStepTap?.
  • Flutter: custom horizontal stepper; vertical on desktop.

AppQRScanner

  • Purpose: biometric check-in, transport pickup, library issue (forward-looking: requires backend QR code support — see assumptions).
  • Props: onScanned, pauseAfterScan, flashToggle?.
  • Flutter: mobile_scanner package (wrap).

F. Shared interaction patterns

  • Pull-to-refresh on all scrollable lists → RefreshIndicator; triggers reload + WS resubscribe.
  • Infinite scroll for paginated lists → bottom CircularProgressIndicator + m-instant fade; "end of list" footer with bodySmall text.
  • Optimistic updates on mark-read, toggles, likes; rollback on error + snackbar.
  • Undo pattern: destructive-ish non-soft actions (delete homework draft, remove attachment) → snackbar with UNDO within 4 s.
  • Empty→loading→error state machine per screen, never blank.

G. Golden-test coverage expectation

Every shared component has a golden test at 3 sizes (phone/tablet/desktop) + dark mode.