👁 Attention & Focus Principles
Attention and focus design is critical for users with ADHD, autism, and other conditions affecting concentration. Clear focus indicators, reduced distractions, and focus mode options help users stay on task.
Design Guidelines
| Principle | Description | Recommendation |
|---|---|---|
| Clear Focus Indicators | Visible keyboard focus | High contrast, 3px minimum outline |
| Reduce Distractions | Minimize interruptions | Avoid flashing ads, unexpected popups |
| Single Task Flow | One thing at a time | Break complex tasks into steps |
| Save Progress | Allow interruptions | Support saving and resuming later |
| Avoid Timeouts | Flexible timing | Provide warnings and extension options |
| Focus Mode | Hide non-essentials | Offer reading/distraction-free mode |
CSS Implementation
/* Clear focus styles */
:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 2px;
}
/* Remove default focus but keep keyboard focus */
:focus:not(:focus-visible) {
outline: none;
}
/* High contrast focus */
.high-contrast-focus:focus-visible {
outline: 4px solid #000000;
outline-offset: 3px;
background-color: #ffff00;
}
/* Custom focus for buttons */
button:focus-visible,
a:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 2px;
border-radius: 4px;
}
React Components
interface FocusModeProps {
children: React.ReactNode;
}
export function FocusMode({ children }: FocusModeProps) {
const [isFocusMode, setIsFocusMode] = useState(false);
return (
<>
<button
onClick={() => setIsFocusMode(true)}
className="btn btn-ghost btn-sm gap-2"
aria-label="Enter focus mode"
>
<Focus className="w-4 h-4" />
Focus Mode
</button>
{isFocusMode && (
<div
className="fixed inset-0 z-50 bg-base-100 overflow-auto"
role="dialog"
aria-modal="true"
aria-label="Focus mode"
>
<div className="max-w-3xl mx-auto p-8">
<button
onClick={() => setIsFocusMode(false)}
className="btn btn-ghost btn-sm btn-circle absolute top-4 right-4"
aria-label="Exit focus mode"
>
<X className="w-5 h-5" />
</button>
{children}
</div>
</div>
)}
</>
);
}
// Progress saving indicator
interface SaveIndicatorProps {
isSaving: boolean;
lastSaved?: Date;
}
export function SaveIndicator({ isSaving, lastSaved }: SaveIndicatorProps) {
return (
<div className="flex items-center gap-2 text-sm text-neutral-500">
{isSaving ? (
<>
<span className="loading loading-spinner loading-xs" />
Saving...
</>
) : lastSaved ? (
<>Saved {lastSaved.toLocaleTimeString()}</>
) : null}
</div>
);
}
Timeout Warning Component
interface TimeoutWarningProps {
timeoutMinutes: number;
warningMinutes: number;
onExtend: () => void;
}
export function TimeoutWarning({
timeoutMinutes,
warningMinutes,
onExtend,
}: TimeoutWarningProps) {
const [showWarning, setShowWarning] = useState(false);
const [timeRemaining, setTimeRemaining] = useState(timeoutMinutes * 60);
useEffect(() => {
const interval = setInterval(() => {
setTimeRemaining((prev) => {
if (prev <= warningMinutes * 60 && prev > 0) {
setShowWarning(true);
}
return prev > 0 ? prev - 1 : 0;
});
}, 1000);
return () => clearInterval(interval);
}, [warningMinutes]);
if (!showWarning) return null;
return (
<div className="fixed bottom-4 right-4 z-50 bg-warning text-warning-content p-4 rounded-lg shadow-lg max-w-sm">
<div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 mt-0.5" />
<div>
<p className="font-semibold">Session Timeout Warning</p>
<p className="text-sm mt-1">
Your session will expire in {Math.floor(timeRemaining / 60)}{" "}
minutes.
</p>
<button
onClick={() => {
onExtend();
setShowWarning(false);
setTimeRemaining(timeoutMinutes * 60);
}}
className="btn btn-sm btn-outline btn-warning-content mt-2"
>
<Clock className="w-4 h-4" />
Extend Session
</button>
</div>
</div>
</div>
);
}
Checklist
- Focus indicators are clearly visible
- Focus has sufficient contrast
- Distractions are minimized
- Complex tasks are broken into steps
- Progress can be saved
- Timeouts have warnings and extension options
- Focus/reading mode is available
- Focus order is logical