Skip to content

[A11Y] [Medium] Interactive divs should use semantic elements #9

@continue

Description

@continue

Accessibility Issue: Interactive Divs Should Use Semantic Elements

WCAG Level: A
Severity: Medium
Category: Keyboard Navigation / Semantic HTML

Issue Description

Several components use <div> elements with click handlers instead of proper semantic elements like <button>. These elements may not be keyboard accessible and lack proper ARIA roles.

User Impact

  • Affected Users: Keyboard-only users, screen reader users
  • Severity: Users cannot activate certain interactive elements with keyboard

Violations Found

File: components/semiconductor/structure-library.tsx

Lines: 118-141

<div
  key={material.id}
  className={`group rounded-lg border bg-zinc-900/50 p-3.5 transition-all cursor-pointer hover:border-zinc-600 ${...}`}
  onClick={() => onSelect(structureToFile(material), material)}
>
  {/* Card content */}
</div>

Issue: Interactive card using <div> with onClick - not keyboard accessible


File: components/calculate/file-upload-section.tsx

Lines: 42-59

<div
  onDrop={handleDrop}
  onDragOver={(e) => e.preventDefault()}
  className="group relative cursor-pointer rounded-lg border-2 border-dashed ..."
>
  <input
    type="file"
    ...
    className="absolute inset-0 cursor-pointer opacity-0"
  />
  ...
</div>

Issue: While the hidden input is accessible, the visual drop zone interaction pattern could be clearer


File: components/semiconductor/defect-generator.tsx

Lines: 133-151

<tr
  key={i}
  onClick={() => setSelectedAtom(i)}
  className={`cursor-pointer border-t border-zinc-800/60 transition-colors hover:bg-zinc-800/40 ...`}
>

Issue: Table rows with click handlers - should be selectable via keyboard


Recommended Fix

For clickable cards:

<!-- Option 1: Use button inside card -->
<div className="group rounded-lg border bg-zinc-900/50 p-3.5">
  <button
    onClick={() => onSelect(structureToFile(material), material)}
    className="w-full text-left focus:outline-none focus:ring-2 focus:ring-matrix-green"
    aria-pressed={isSelected}
  >
    {/* Card content */}
  </button>
</div>

<!-- Option 2: Make entire div a button -->
<button
  className="group rounded-lg border bg-zinc-900/50 p-3.5 text-left w-full focus:outline-none focus:ring-2 focus:ring-matrix-green"
  onClick={() => onSelect(structureToFile(material), material)}
  aria-pressed={isSelected}
>
  {/* Card content */}
</button>

For selectable table rows:

<tr
  key={i}
  onClick={() => setSelectedAtom(i)}
  onKeyDown={(e) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      setSelectedAtom(i);
    }
  }}
  tabIndex={0}
  role="button"
  aria-pressed={selectedAtom === i}
  className="cursor-pointer ... focus:outline-none focus:ring-2 focus:ring-inset focus:ring-matrix-green"
>

Changes Made:

  1. Use <button> instead of <div> for clickable elements
  2. If <div> must be used, add role="button", tabIndex={0}, and keyboard handlers
  3. Add aria-pressed for toggle-like interactions
  4. Ensure focus styles are visible

Additional Instances

  • Category filter pills in components/semiconductor/structure-library.tsx (these are already buttons - good!)
  • Expandable sections in components/calculate/parameter-panel.tsx

Testing Instructions

  1. Tab through all interactive elements
  2. Verify all clickable items receive focus
  3. Press Enter/Space on focused elements
  4. Verify action is triggered

Resources

Acceptance Criteria

  • All interactive elements are keyboard accessible
  • Focus indicator visible on all elements
  • Enter/Space activates clickable elements
  • Proper ARIA roles where semantic elements not used

Metadata

Metadata

Assignees

No one assigned

    Labels

    accessibilityWeb accessibility improvements (WCAG compliance)severity-mediumMedium severity issuewcag-aWCAG Level A compliance

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions