Skip to content

Commit 83ef53b

Browse files
committed
fix(a11y): give clickable thumbnails, icon tiles and a pseudo-link real semantics
Three more click targets with no keyboard path. DocumentThumbnail repeats its onClick across four render branches, so the semantics are built once and only when a handler was actually given — a decorative thumbnail should not take a tab stop. The OCR setup-guide text was styled as a link and opened one, but was a Text with an onClick: unreachable by keyboard and no target cue on hover. It is now an anchor. IconSelector's tiles are choices, so they say so, and each carries the label its tooltip already showed.
1 parent 33dee96 commit 83ef53b

3 files changed

Lines changed: 37 additions & 10 deletions

File tree

frontend/editor/src/core/components/shared/filePreview/DocumentThumbnail.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
3333
}) => {
3434
if (!file) return null;
3535

36+
// A thumbnail that takes a click is a control; without these it is a div, so
37+
// the file cannot be opened by keyboard. Only applied when a handler was
38+
// given — a decorative thumbnail should not take a tab stop.
39+
const interactive = onClick
40+
? {
41+
role: "button",
42+
tabIndex: 0,
43+
onClick,
44+
onKeyDown: (e: React.KeyboardEvent<HTMLElement>) => {
45+
if (e.key === "Enter" || e.key === " ") {
46+
e.preventDefault();
47+
onClick();
48+
}
49+
},
50+
}
51+
: {};
52+
3653
const containerStyle: React.CSSProperties = {
3754
position: "relative",
3855
cursor: onClick ? "pointer" : "default",
@@ -47,7 +64,7 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
4764

4865
if (thumbnail && !isEncrypted) {
4966
return (
50-
<Box style={containerStyle} onClick={onClick}>
67+
<Box style={containerStyle} {...interactive}>
5168
<PrivateContent>
5269
<img
5370
src={thumbnail}
@@ -77,7 +94,7 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
7794

7895
if (isEncrypted) {
7996
return (
80-
<Box style={containerStyle} onClick={onClick}>
97+
<Box style={containerStyle} {...interactive}>
8198
<div
8299
style={{
83100
display: "flex",
@@ -116,7 +133,7 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
116133

117134
if (isLoading) {
118135
return (
119-
<Box style={containerStyle} onClick={onClick}>
136+
<Box style={containerStyle} {...interactive}>
120137
<Stack
121138
align="center"
122139
justify="center"
@@ -136,7 +153,7 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
136153
const ext = detectFileExtension(file.name ?? "").toUpperCase();
137154

138155
return (
139-
<Box style={containerStyle} onClick={onClick}>
156+
<Box style={containerStyle} {...interactive}>
140157
<Center
141158
style={{
142159
width: "100%",

frontend/editor/src/core/components/tools/automate/IconSelector.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,16 @@ export default function IconSelector({
9292
return (
9393
<Tooltip key={option.value} label={option.label}>
9494
<Box
95+
role="button"
96+
tabIndex={0}
97+
aria-label={option.label}
9598
onClick={() => handleIconSelect(option.value)}
99+
onKeyDown={(e) => {
100+
if (e.key === "Enter" || e.key === " ") {
101+
e.preventDefault();
102+
handleIconSelect(option.value);
103+
}
104+
}}
96105
style={{
97106
display: "flex",
98107
alignItems: "center",

frontend/editor/src/core/components/tools/ocr/LanguagePicker.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,20 +155,21 @@ const LanguagePicker: React.FC<LanguagePickerProps> = ({
155155
"Looking for additional languages?",
156156
)}
157157
</Text>
158+
{/* A real anchor: it was styled as a link and opened one, but as a
159+
Text with an onClick it could not be reached by keyboard and gave
160+
no target cue on hover. */}
158161
<Text
162+
component="a"
163+
href="https://docs.stirlingpdf.com/Configuration/OCR"
164+
target="_blank"
165+
rel="noopener noreferrer"
159166
size="xs"
160167
style={{
161168
color: "var(--c-accent-text)",
162169
cursor: "pointer",
163170
textDecoration: "underline",
164171
textAlign: "center",
165172
}}
166-
onClick={() =>
167-
window.open(
168-
"https://docs.stirlingpdf.com/Configuration/OCR",
169-
"_blank",
170-
)
171-
}
172173
>
173174
{t("ocr.languagePicker.viewSetupGuide", "View setup guide →")}
174175
</Text>

0 commit comments

Comments
 (0)