-
Notifications
You must be signed in to change notification settings - Fork 961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Onboarding page added aria-lable
and keyboard navigation
#1562
Conversation
@harsh9975 is attempting to deploy a commit to the formbricks Team on Vercel. A member of the Team first needs to authorize it. |
Thank you for following the naming conventions for pull request titles! 🙏 |
packages/ui/ColorPicker/index.tsx, apps/web/app/(app)/onboarding/components/Product.tsxAdding aria-labels to input fields can improve accessibility by providing more context to screen readers. This can be particularly helpful for users who rely on assistive technologies. <HexColorInput
className="ml-2 mr-2 h-10 w-32 flex-1 border-0 bg-transparent text-slate-500 outline-none focus:border-none"
color={color}
onChange={onChange}
id="color"
aria-label="Primary color"
/>
<Input
id="product"
type="text"
placeholder="e.g. Formbricks"
value={name}
onChange={handleNameChange}
aria-label="Your product name"
/> apps/web/app/(app)/onboarding/components/Greeting.tsxAdding keyboard accessibility to buttons can improve the user experience for those who rely on keyboard navigation. This can be achieved by adding a keydown event listener that triggers the button's action when the 'Enter' key is pressed. useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Enter") {
event.preventDefault();
next();
}
};
const button = buttonRef.current;
if (button) {
button.focus();
button.addEventListener("keydown", handleKeyDown);
}
return () => {
if (button) {
button.removeEventListener("keydown", handleKeyDown);
}
};
}, []); apps/web/app/(app)/onboarding/components/Role.tsxAdding keyboard accessibility to radio buttons can improve the user experience for those who rely on keyboard navigation. This can be achieved by adding a keydown event listener that changes the focus and selected value when the 'Tab' key is pressed. useEffect(() => {
const handleKeydown = (event: KeyboardEvent) => {
if (event.key === "Tab") {
event.preventDefault();
const radioButtons = fieldsetRef.current?.querySelectorAll('input[type="radio"]');
if (radioButtons && radioButtons.length > 0) {
const focusedRadioButton = fieldsetRef.current?.querySelector(
'input[type="radio"]:focus'
) as HTMLInputElement;
if (!focusedRadioButton) {
// If no radio button is focused, by default the first element will be focused
const firstRadioButton = radioButtons[0] as HTMLInputElement;
firstRadioButton.focus();
setSelectedChoice(firstRadioButton.value);
} else {
const focusedIndex = Array.from(radioButtons).indexOf(focusedRadioButton);
// If the last element is focused, set it back to the first one or change it to the next element
if (focusedIndex === radioButtons.length - 1) {
const firstRadioButton = radioButtons[0] as HTMLInputElement;
firstRadioButton.focus();
setSelectedChoice(firstRadioButton.value);
} else {
const nextRadioButton = radioButtons[focusedIndex + 1] as HTMLInputElement;
nextRadioButton.focus();
setSelectedChoice(nextRadioButton.value);
}
}
}
}
};
window.addEventListener("keydown", handleKeydown);
return () => {
window.removeEventListener("keydown", handleKeydown);
};
}, []); Adding the htmlFor attribute to label elements can improve accessibility by creating an explicit association between the label and its corresponding input element. This can be particularly helpful for users who rely on assistive technologies. <label
key={choice.id}
htmlFor={choice.id}
className={cn(
selectedChoice === choice.label
? "z-10 border-slate-400 bg-slate-100"
: "border-gray-200",
"relative flex cursor-pointer flex-col rounded-md border p-4 hover:bg-slate-100 focus:outline-none"
)}>
<span className="flex items-center text-sm">
<input
type="radio"
id={choice.id}
value={choice.label}
name="role"
checked={choice.label === selectedChoice}
className="checked:text-brand-dark focus:text-brand-dark h-4 w-4 border border-gray-300 focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${choice.id}-label`}
onChange={(e) => {
setSelectedChoice(e.currentTarget.value);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleNextClick();
}
}}
/>
<span id={`${choice.id}-label`} className="ml-3 font-medium">
{choice.label}
</span>
</span>
</label> apps/web/app/(app)/onboarding/components/Objective.tsxThe current implementation of keyboard navigation is inefficient as it queries the DOM every time the 'Tab' key is pressed. This can be improved by storing the radio buttons in a state variable and updating it only when the component mounts or updates. const [radioButtons, setRadioButtons] = useState<NodeListOf<HTMLInputElement> | null>(null);
useEffect(() => {
setRadioButtons(fieldsetRef.current?.querySelectorAll('input[type="radio"]'));
}, []);
useEffect(() => {
const handleKeydown = (event: KeyboardEvent) => {
if (event.key === "Tab" && radioButtons) {
event.preventDefault();
const focusedRadioButton = document.activeElement as HTMLInputElement;
if (!focusedRadioButton) {
const firstRadioButton = radioButtons[0];
firstRadioButton.focus();
setSelectedChoice(firstRadioButton.value);
} else {
const focusedIndex = Array.from(radioButtons).indexOf(focusedRadioButton);
if (focusedIndex === radioButtons.length - 1) {
const firstRadioButton = radioButtons[0];
firstRadioButton.focus();
setSelectedChoice(firstRadioButton.value);
} else {
const nextRadioButton = radioButtons[focusedIndex + 1];
nextRadioButton.focus();
setSelectedChoice(nextRadioButton.value);
}
}
}
};
window.addEventListener("keydown", handleKeydown);
return () => {
window.removeEventListener("keydown", handleKeydown);
};
}, [radioButtons]); The code for handling the 'Tab' key press is quite long and complex. It can be simplified by extracting the logic for focusing on the next radio button into a separate function. const focusNextRadioButton = (radioButtons: NodeListOf<HTMLInputElement>, currentRadioButton: HTMLInputElement | null) => {
const focusedIndex = currentRadioButton ? Array.from(radioButtons).indexOf(currentRadioButton) : -1;
const nextIndex = (focusedIndex + 1) % radioButtons.length;
const nextRadioButton = radioButtons[nextIndex];
nextRadioButton.focus();
setSelectedChoice(nextRadioButton.value);
};
useEffect(() => {
const handleKeydown = (event: KeyboardEvent) => {
if (event.key === "Tab" && radioButtons) {
event.preventDefault();
const focusedRadioButton = document.activeElement as HTMLInputElement;
focusNextRadioButton(radioButtons, focusedRadioButton);
}
};
window.addEventListener("keydown", handleKeydown);
return () => {
window.removeEventListener("keydown", handleKeydown);
};
}, [radioButtons]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @harsh9975 , functionality works very well 🚀😍, I just left a comment involving some refactoring tips. After those changes we are good to go !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the changes. Looks great 😊🚀
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Ignored Deployments
|
What does this PR do?
This PR was regarding issue #1552 added
aria-label
in all inputs and #1551 implemented keyboard navigationhowever there is a small doubt
in radio group button while navigating through the page it only focuses on 1st radio button, in-order to navigate in all radio buttons I used useRef.
if there are any changes or suggestion you can guide me.
Fixes # (issue)
#1551
#1552
Type of change
How should this be tested?
-create an account
Checklist
Required
pnpm build
console.logs
git pull origin main
Appreciated