a11y(web-dashboard): add aria labels, roles, and live regions to interactive components

- EmergencyControls: aria-label on all buttons and confirmation input
- OrderForm: aria-label and aria-pressed on buy/sell toggle buttons
- DashboardLayout: aria-label on navigation
- StatusBar: aria-live on connection status, aria-hidden on decorative indicator dot

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-02-22 08:06:46 +01:00
parent 5b96d64432
commit f930b4f1b7
4 changed files with 12 additions and 2 deletions

View File

@@ -36,7 +36,7 @@ export function DashboardLayout({ children }: Props) {
return (
<div className="flex flex-col h-screen">
{/* Top navigation */}
<nav className="flex items-center gap-1 px-4 py-2 bg-[var(--color-bg-secondary)] border-b border-[var(--color-border)]">
<nav aria-label="Dashboard navigation" className="flex items-center gap-1 px-4 py-2 bg-[var(--color-bg-secondary)] border-b border-[var(--color-border)]">
<span className="text-sm font-bold text-[var(--color-accent)] mr-4">FOXHUNT</span>
{NAV_ITEMS.map((item) => (
<NavLink

View File

@@ -12,11 +12,12 @@ export function StatusBar() {
return (
<footer className="flex items-center justify-between px-4 py-1 text-xs bg-[var(--color-bg-secondary)] border-t border-[var(--color-border)] text-[var(--color-text-secondary)]">
<div className="flex items-center gap-4">
<span className="flex items-center gap-1">
<span className="flex items-center gap-1" aria-live="polite">
<span
className={`inline-block w-2 h-2 rounded-full ${
connected ? 'bg-[var(--color-green)]' : 'bg-[var(--color-red)]'
}`}
aria-hidden="true"
/>
WS: {connected ? 'Connected' : 'Disconnected'}
</span>
@@ -29,6 +30,7 @@ export function StatusBar() {
{authenticated && (
<button
onClick={logout}
aria-label="Sign out of the trading system"
className="text-[var(--color-text-secondary)] hover:text-[var(--color-red)] transition-colors"
>
Sign Out

View File

@@ -26,6 +26,7 @@ export function EmergencyControls() {
{!showConfirm ? (
<button
onClick={() => setShowConfirm(true)}
aria-label="Trigger emergency stop — cancels all orders and closes all positions"
className="w-full py-3 text-sm font-bold rounded bg-[var(--color-red)] text-white hover:bg-red-600 transition-colors"
>
EMERGENCY STOP
@@ -40,6 +41,7 @@ export function EmergencyControls() {
value={confirmText}
onChange={(e) => setConfirmText(e.target.value)}
placeholder="Type STOP"
aria-label="Type STOP to confirm emergency shutdown"
className="w-full px-2 py-1.5 text-sm rounded border border-[var(--color-red)] bg-[var(--color-bg-primary)] text-[var(--color-text-primary)] outline-none"
autoFocus
/>
@@ -49,6 +51,7 @@ export function EmergencyControls() {
setShowConfirm(false);
setConfirmText('');
}}
aria-label="Cancel emergency stop"
className="py-1.5 text-xs rounded border border-[var(--color-border)] text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]"
>
Cancel
@@ -56,6 +59,7 @@ export function EmergencyControls() {
<button
onClick={handleEmergencyStop}
disabled={confirmText !== 'STOP' || emergencyStop.isPending}
aria-label="Confirm emergency stop"
className="py-1.5 text-xs rounded bg-[var(--color-red)] text-white disabled:opacity-50"
>
{emergencyStop.isPending ? 'Stopping...' : 'Confirm STOP'}

View File

@@ -64,6 +64,8 @@ export function OrderForm() {
<button
type="button"
onClick={() => setSide('buy')}
aria-label="Set order side to buy"
aria-pressed={side === 'buy'}
className={`py-1.5 text-sm rounded font-medium transition-colors ${
side === 'buy'
? 'bg-[var(--color-green)] text-white'
@@ -75,6 +77,8 @@ export function OrderForm() {
<button
type="button"
onClick={() => setSide('sell')}
aria-label="Set order side to sell"
aria-pressed={side === 'sell'}
className={`py-1.5 text-sm rounded font-medium transition-colors ${
side === 'sell'
? 'bg-[var(--color-red)] text-white'