Skip to content

feat(forms): add skeleton loading state - #1090

Open
khaylebfortune wants to merge 3 commits into
Talenttrust:mainfrom
khaylebfortune:feature/forms-72-skeleton
Open

feat(forms): add skeleton loading state#1090
khaylebfortune wants to merge 3 commits into
Talenttrust:mainfrom
khaylebfortune:feature/forms-72-skeleton

Conversation

@khaylebfortune

@khaylebfortune khaylebfortune commented Jul 31, 2026

Copy link
Copy Markdown

Summary

Extracts a dedicated FormsListSkeleton component that mirrors the FormsList layout to prevent layout shift during loading. Uses SkeletonContainer for accessible loading announcements to assistive technology.

Changes

File Change
src/components/FormsList.tsx Extracted FormsListSkeleton component with filter buttons, export buttons, and 10 form rows with title + ID + copy button placeholders. Error-in-loading support: error banner shown inside skeleton container. Uses SkeletonContainer for accessibility.
src/components/Skeleton.tsx Extended SkeletonContainerProps to inherit React.HTMLAttributes<HTMLDivElement>. Guards ARIA attributes from accidental override.
src/components/__tests__/FormsListSkeleton.test.tsx New — 20 tests: rendering, accessibility, axe, structure, transitions, mutual exclusivity, no-layout-shift, error-in-loading.
src/components/__tests__/FormsList.test.tsx Updated tests for new error-in-loading behavior and skeleton structure.

Test Results

FormsList: 4 suites, 103 tests — all passing
Skeleton:  7 suites, 92 tests  — all passing
Total:     11 suites, 195 tests — all passing

Key Design Decisions

  • SkeletonContainer pattern — follows CreateStreamFormSkeleton pattern (role=status, aria-busy=true, aria-live=polite, sr-only label)
  • Layout matching — skeleton toolbar and rows mirror the exact Flexbox classes of the loaded state
  • Error-in-loading — when both isLoading and error are set, the loading container shows an error banner inside (skeleton rows hidden); AT still hears "Loading forms" while sighted users see the error
  • ARIA guardSkeletonContainer destructures ARIA attributes from rest props to prevent overrides

Closes #1025

- Improve loading skeleton to mirror loaded layout exactly, preventing
  layout shift (add export button placeholders, match row structure
  with title + id + copy button skeletons)
- Skeleton announces loading to AT via role=status, aria-label,
  aria-live=polite, aria-busy=true, and sr-only span
- Add 9 comprehensive tests covering: toolbar mirroring, row structure
  matching, placeholder contents, axe accessibility, skeleton→content
  transitions, and state exclusivity during loading

Closes Talenttrust#1025
Extract FormsListSkeleton component that mirrors the FormsList layout
(filter buttons, export buttons, form rows with title + ID + copy button)
to prevent layout shift during loading.

- Use SkeletonContainer for accessible loading announcement (role=status,
  aria-busy=true, aria-live=polite)
- Extend SkeletonContainerProps to accept HTML div attributes (data-testid)
- Guard ARIA attributes from accidental override via rest props
- Add 20 comprehensive tests for skeleton rendering, accessibility,
  transitions, and axe compliance
- Loading skeleton now takes precedence over error prop

Closes Talenttrust#1025
- Add forms-skeleton-filters and forms-skeleton-export test IDs
- Use <span> for right group in skeleton rows (matches loaded layout)
- Support error-in-loading: show error banner inside skeleton container
- Update tests to match new error-in-loading behavior
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a skeleton loading state to forms

1 participant