All Docs
FeaturesDepositClearUpdated March 11, 2026

Fixing Focus Traps & Auto-Open Surprises in the Wear & Tear Slide-Over

Fixing Focus Traps & Auto-Open Surprises in the Wear & Tear Slide-Over

Release v0.1.105 · Accessibility · Deduction Claim Builder


Background

The Deduction Claim Builder lets landlords and agents itemise deposit deductions category by category. Alongside the main AddDeductionDialog, a Wear & Tear (W&T) Guide slide-over panel provides contextual guidance on what counts as fair wear and tear versus chargeable damage.

In practice, two bugs made this flow difficult — and in some cases unusable — for people relying on keyboard navigation or screen readers.


The Problems

1. Focus was never moved into the slide-over

AddDeductionDialog renders with a z-50 backdrop. WearTearSlideOver was rendered outside that backdrop (noted in the code comments) and used its own z-40/z-50 stack. When the slide-over opened, the browser's focus remained inside the dialog behind it. A screen reader user received no announcement that anything had changed, and keyboard focus stayed trapped in the wrong layer.

2. The slide-over opened without being asked

Whenever a user selected a deduction category for a new deduction, the application automatically opened the W&T Guide:

// Previous behaviour — triggered on every category selection
if (cat && !editDeduction) {
  setSlideOverOpen(true)
}

This auto-open had two downsides:

  • It interrupted the user's flow with content they may not have wanted.
  • It moved the visual focus point unpredictably, compounding the focus-trap problem described above.

What We Fixed

Auto-open removed

The conditional setSlideOverOpen(true) call on category selection has been removed. The W&T Guide now opens only when the user explicitly clicks the W&T Guide button. The principle of least surprise is restored — the UI does what the user asks, nothing more.

Proper ARIA semantics

WearTearSlideOver now declares itself correctly to assistive technology:

<div role="dialog" aria-modal="true" aria-label="Wear & Tear Guide">
  <!-- slide-over content -->
</div>

aria-modal="true" signals to screen readers that content outside the slide-over should be treated as inert while it is open.

Focus management on open

When the slide-over opens, focus is programmatically moved to the first interactive element inside it (typically the close button or the first navigable section heading). A self-contained focus trap keeps keyboard navigation within the panel until it is dismissed.

Live region announcement

An aria-live="polite" region fires when the slide-over opens, giving screen reader users an explicit cue:

<div aria-live="polite" aria-atomic="true">
  {slideOverOpen ? 'Wear & Tear Guide opened.' : ''}
</div>

Escape key scoped correctly

Previously, pressing Esc could close the parent AddDeductionDialog rather than the slide-over in front of it. The key handler is now scoped so that Esc closes only the slide-over — the dialog behind it remains open and in its current state.


Impact

User groupBeforeAfter
Keyboard-only usersFocus trapped behind slide-over; could not navigate guide contentFocus moves into slide-over; full keyboard nav available
Screen reader usersNo announcement on slide-over open; no modal boundaryaria-live announcement fires; aria-modal marks boundary
All usersSlide-over opened automatically on category pickSlide-over opens only on explicit button click

Affected Component

src/app/dashboard/deductions/[tenancyId]/deduction-claim-builder.tsx

No changes to data models, API routes, or stored deduction records.