From 7e2de5a26cdafb317f23acc728f5072c33508377 Mon Sep 17 00:00:00 2001 From: Chris Arderne Date: Wed, 19 Aug 2026 11:38:23 +0100 Subject: [PATCH 1/2] fix(webapp): use native checkbox label semantics --- .oxlintrc.json | 2 +- .../app/components/primitives/Checkbox.tsx | 20 ++++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 37048cb4171..7c01c520b74 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -86,7 +86,7 @@ ], "jsx-a11y/label-has-associated-control": "error", "jsx-a11y/no-autofocus": "off", - "jsx-a11y/no-noninteractive-element-interactions": "off", + "jsx-a11y/no-noninteractive-element-interactions": "error", "jsx-a11y/no-static-element-interactions": "off", "jsx-a11y/prefer-tag-over-role": "off", "jsx-a11y/anchor-ambiguous-text": "error", diff --git a/apps/webapp/app/components/primitives/Checkbox.tsx b/apps/webapp/app/components/primitives/Checkbox.tsx index da63e2ed993..2ac12da35ca 100644 --- a/apps/webapp/app/components/primitives/Checkbox.tsx +++ b/apps/webapp/app/components/primitives/Checkbox.tsx @@ -109,7 +109,7 @@ export const CheckboxWithLabel = React.forwardRef { - //returning false is not setting the state to false, it stops the event from bubbling up - if (isDisabled || props.readOnly === true) return false; - setIsChecked((c) => !c); - }} > { - //returning false is not setting the state to false, it stops the event from bubbling up - if (isDisabled || props.readOnly === true) return false; - setIsChecked(!isChecked); + if (isDisabled || props.readOnly === true) return; + setIsChecked(e.target.checked); }} disabled={isDisabled} className={cn( @@ -150,17 +144,15 @@ export const CheckboxWithLabel = React.forwardRef
- + {badges && ( {badges.map((badge) => ( @@ -175,7 +167,7 @@ export const CheckboxWithLabel = React.forwardRef )}
-
+ ); } ); From 098f636ca23233b28d2640b0b3e8edfdbbacc7ab Mon Sep 17 00:00:00 2001 From: Chris Arderne Date: Wed, 19 Aug 2026 12:50:47 +0100 Subject: [PATCH 2/2] fix(webapp): separate checkbox names and descriptions --- .../app/components/primitives/Checkbox.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/webapp/app/components/primitives/Checkbox.tsx b/apps/webapp/app/components/primitives/Checkbox.tsx index 2ac12da35ca..8db6defb4ac 100644 --- a/apps/webapp/app/components/primitives/Checkbox.tsx +++ b/apps/webapp/app/components/primitives/Checkbox.tsx @@ -86,6 +86,12 @@ export const CheckboxWithLabel = React.forwardRef { const [isChecked, setIsChecked] = useState(defaultChecked ?? false); const [isDisabled, setIsDisabled] = useState(disabled ?? false); + const generatedId = React.useId(); + const inputId = id ?? generatedId; + const labelId = `${inputId}-label`; + const descriptionId = `${inputId}-description`; + const ariaLabelledBy = + props["aria-label"] || props["aria-labelledby"] ? props["aria-labelledby"] : labelId; const buttonClassName = variants[variant].button; const labelClassName = variants[variant].label; @@ -125,6 +131,11 @@ export const CheckboxWithLabel = React.forwardRef { if (isDisabled || props.readOnly === true) return; setIsChecked(e.target.checked); @@ -139,12 +150,13 @@ export const CheckboxWithLabel = React.forwardRef
{variant === "description" && ( - + {description} )}