Skip to content

Commit

Permalink
Improve keyboard accessibility of the codecard component (#10405)
Browse files Browse the repository at this point in the history
  • Loading branch information
microbit-robert authored Mar 6, 2025
1 parent 625364a commit b64e8c2
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 7 deletions.
28 changes: 22 additions & 6 deletions webapp/src/codecard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ export class CodeCardView extends data.Component<CodeCardProps, CodeCardState> {
card.onClick(e);
} : undefined;

const keydownHandler = (e: React.KeyboardEvent) => {
const charCode = (typeof e.which == "number") ? e.which : e.keyCode;
if (charCode === /*enter*/13 || charCode === /*space*/32) {
clickHandler(e);
}
}

const imageUrl = card.imageUrl || (card.youTubeId ? `https://img.youtube.com/vi/${card.youTubeId}/0.jpg` : undefined);

// these header-derived properties must be taken from the virtual API system, not the props. Otherwise
Expand All @@ -95,9 +102,18 @@ export class CodeCardView extends data.Component<CodeCardProps, CodeCardState> {
const ariaLabel = card.ariaLabel || card.title || card.shortName || name;

const style = card.style || "card"
const cardDiv = <div className={`ui ${style} ${color} ${card.onClick ? "link" : ''} ${className ? className : ''}`}
role={card.role} aria-selected={card.role === "option" ? "true" : undefined} aria-label={ariaLabel} title={card.title}
onClick={clickHandler} tabIndex={card.onClick ? card.tabIndex || 0 : null} onKeyDown={card.onClick ? fireClickOnEnter : null}>

const renderButton = (content: JSX.Element) => {
return (<div className={`ui ${style} ${color} ${card.onClick ? "link" : ''} ${className ? className : ''}`}
role={card.role} aria-selected={card.role === "option" ? "true" : undefined} aria-label={ariaLabel} title={card.title}
onClick={clickHandler} tabIndex={card.onClick ? card.tabIndex || 0 : null} onKeyDown={keydownHandler}>{content}</div>)
}
const renderLink = (content: JSX.Element) => {
return (<a href={url} className={`ui ${style} ${color} link ${className ? className : ''}`}
aria-label={ariaLabel} title={card.title}>{content}</a>)
}

const cardContent = <>
{card.header ?
<div key="header" className={"ui content " + (card.responsive ? " tall desktop only" : "")}>
{card.header}
Expand Down Expand Up @@ -169,12 +185,12 @@ export class CodeCardView extends data.Component<CodeCardProps, CodeCardState> {
{lf("Feedback")}
</a> : undefined}
</div> : undefined}
</div>;
</>;

if (!card.onClick && url) {
return <a href={url}>{cardDiv}</a>;
return (renderLink(cardContent))
} else {
return (cardDiv)
return (renderButton(cardContent))
}
}
}
2 changes: 1 addition & 1 deletion webapp/src/scriptsearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ export class ScriptSearch extends data.Component<ISettingsProps, ScriptSearchSta
/>}
{showOpenBeta && <codecard.CodeCardView
ariaLabel={lf("Open the next version of the editor")}
role="button"
role="link"
key={'beta'}
className="beta"
icon="lab ui cardimage"
Expand Down

0 comments on commit b64e8c2

Please sign in to comment.