Start with the policy boundary
Before drawing the state, name who owns the deadline, the timezone, whether approval can complete after expiry, who may re-request it, which submitted snapshot remains visible, and what is retained. The service or policy—not a browser timer—decides whether a request has expired.
Do not use expired as a softer label for rejected. Rejection records a reviewer decision; expiry means the allowed review window ended. They can have different recovery paths, records, and audit implications.
Make state and next action visible
| State | What the interface must say | Next action |
|---|---|---|
| Pending | Who can decide and the stated review deadline. | Wait, withdraw, or inspect details under policy. |
| Expiring | Deadline and timezone, plus what will happen. | Finish review if authorized. |
| Expired | This request is no longer reviewable; it was not rejected. | View snapshot, re-request if policy permits, or escalate. |
| Rejected | Reviewer decision and reason where policy allows. | Address feedback or submit a new request. |
| Re-requested | The new request is distinct from the old one. | Review under its own deadline. |
Show the submitted snapshot, request ID, expiry time, and policy reference on an expired request. If policy allows a replacement, clearly say that it creates a new request—not that it revives the old one.
Use text, not color or disappearance alone
W3C's error-identification guidance requires detected input errors to be identified and described in text. Expiry is a policy state rather than necessarily an input error, but the same practical lesson applies: a color change, disabled button, or disappearing control cannot be the only explanation of a consequential change.
Render a stable role="status" aria-atomic="true" container before ordinary pending, expiring, or expired updates where it fits. W3C's ARIA22 technique describes this as a polite status-message pattern that does not require moving focus and notes why atomic context can matter. Keep an actionable re-request or escalation control visibly labeled and keyboard reachable.
Review the complete state map
evidence/P99/expired-approval-state-map.md identifies visible text, retained context, allowed action, and the trusted-service boundary for six related states. It is an acceptance artifact, not a browser, policy, or accessibility test result.
Acceptance checklist
- Deadline includes timezone and named policy or service authority.
- Expired and rejected have distinct visible text and records.
- Snapshot and request ID remain available after expiry.
- A replacement request is clearly new and has its own deadline.
- Re-request and escalation actions stay visible and keyboard reachable.
- Backend owns deadline, authorization, decision, and retention.
Can an approver simply approve an expired request?
Only if policy explicitly permits that transition and the service records it. Do not leave a still-active Approve button as an undocumented exception.