@@ -97,13 +97,48 @@ const initialProducts: Product[] = [
9797 } ,
9898]
9999
100+ // UX BUG: Checkbox only toggles when the click lands very close to its center.
101+ // It looks and behaves like a normal checkbox otherwise, so users won't understand
102+ // why their clicks sometimes "miss".
103+ const CLICK_RADIUS = 4 // pixels from center that count as a hit
104+
105+ function TinyCheckbox ( {
106+ checked,
107+ onChange,
108+ ariaLabel,
109+ } : {
110+ checked : boolean
111+ onChange : ( ) => void
112+ ariaLabel : string
113+ } ) {
114+ return (
115+ < input
116+ type = "checkbox"
117+ checked = { checked }
118+ onChange = { ( ) => {
119+ // no-op: we handle toggling via onPointerDown
120+ } }
121+ onPointerDown = { ( e ) => {
122+ e . preventDefault ( )
123+ const rect = ( e . target as HTMLElement ) . getBoundingClientRect ( )
124+ const cx = rect . left + rect . width / 2
125+ const cy = rect . top + rect . height / 2
126+ const dx = e . clientX - cx
127+ const dy = e . clientY - cy
128+ if ( Math . sqrt ( dx * dx + dy * dy ) <= CLICK_RADIUS ) {
129+ onChange ( )
130+ }
131+ } }
132+ className = "cursor-pointer accent-primary"
133+ aria-label = { ariaLabel }
134+ />
135+ )
136+ }
137+
100138function ProductTableBulkDelete ( ) {
101139 const [ products , setProducts ] = useState ( initialProducts )
102140 const [ selected , setSelected ] = useState < Set < number > > ( new Set ( ) )
103141
104- // BUG: the checkbox click targets are tiny — only the checkbox itself is clickable,
105- // not the surrounding cell or row. Normally the clickable area should be much larger.
106-
107142 function toggleRow ( id : number ) {
108143 setSelected ( ( prev ) => {
109144 const next = new Set ( prev )
@@ -177,12 +212,10 @@ function ProductTableBulkDelete() {
177212 < TableHeader >
178213 < TableRow >
179214 < TableHead className = "w-10" >
180- < input
181- type = "checkbox"
215+ < TinyCheckbox
182216 checked = { allSelected }
183217 onChange = { toggleAll }
184- className = "cursor-pointer accent-primary"
185- aria-label = "Select all products"
218+ ariaLabel = "Select all products"
186219 />
187220 </ TableHead >
188221 < TableHead className = "text-xs" > Product</ TableHead >
@@ -208,12 +241,10 @@ function ProductTableBulkDelete() {
208241 className = { selected . has ( p . id ) ? "bg-muted/50" : "" }
209242 >
210243 < TableCell >
211- < input
212- type = "checkbox"
244+ < TinyCheckbox
213245 checked = { selected . has ( p . id ) }
214246 onChange = { ( ) => toggleRow ( p . id ) }
215- className = "cursor-pointer accent-primary"
216- aria-label = { `Select ${ p . name } ` }
247+ ariaLabel = { `Select ${ p . name } ` }
217248 />
218249 </ TableCell >
219250 < TableCell > { p . name } </ TableCell >
@@ -256,21 +287,20 @@ export const productTableBulkDelete: MiniAppDefinition = {
256287 introduction :
257288 "A product inventory table with checkboxes for selecting rows and performing bulk actions." ,
258289 category : "lists" ,
259- difficulty : "hard " ,
290+ difficulty : "medium " ,
260291 component : ProductTableBulkDelete ,
261292 expectedAnswers : [
262- "The checkboxes have a very small click target — you have to click exactly on the tiny checkbox." ,
263- "The clickable area for selecting rows is too small. Only the checkbox itself is clickable, not the cell or row." ,
264- "The hit area for the checkboxes is tiny. Clicking near the checkbox but not exactly on it does nothing." ,
265- "The selection checkboxes are hard to click because the click target doesn't extend to the full cell." ,
266- "You have to precisely aim at the small checkbox to select a row. The surrounding area is not clickable." ,
267- "The checkbox click targets are too small — the row or cell should also toggle the selection." ,
268- "Clicking the table cell around the checkbox doesn't toggle it, only clicking the tiny checkbox itself works." ,
269- "The checkboxes are small and hard to click. The clickable zone should be larger than just the checkbox." ,
270- "Clicking anywhere on the row should toggle the selection, but only the tiny checkbox works." ,
271- "The entire row should be clickable to select it, but you have to click the small checkbox precisely." ,
293+ "The checkboxes only register clicks if you hit the exact center. Clicking slightly off-center does nothing." ,
294+ "The checkboxes seem broken or unresponsive. Most clicks don't register because the hit area is tiny." ,
295+ "Clicking the checkboxes often doesn't work. You have to aim very precisely at the center of the checkbox." ,
296+ "The checkboxes have an extremely small clickable area. Clicks near the edge of the checkbox are ignored." ,
297+ "The selection checkboxes are frustrating to use because only clicks in the dead center actually toggle them." ,
298+ "The checkboxes look normal but don't respond to most clicks. The active click target is much smaller than the visible checkbox." ,
299+ "It's very hard to select rows because the checkboxes require pixel-perfect clicking to toggle." ,
300+ "The checkboxes are unreliable — sometimes they work and sometimes they don't, depending on where exactly you click." ,
301+ "The checkbox hit targets are too small. You have to click the exact center pixel for them to register." ,
272302 ] ,
273- hint : "Try selecting rows." ,
303+ hint : "Try selecting several rows quickly ." ,
274304 wrongAnswers : [
275305 "There is no way to deselect items or clear the selection." ,
276306 "The confirmation dialog is missing or unclear." ,
0 commit comments