Skip to content

๐ŸŽจ Palette: [UX improvement] Add ARIA disabled state to editor save button - #577

Closed
seonghobae wants to merge 1 commit into
developfrom
palette/aria-disabled-save-5071278339747262059
Closed

๐ŸŽจ Palette: [UX improvement] Add ARIA disabled state to editor save button#577
seonghobae wants to merge 1 commit into
developfrom
palette/aria-disabled-save-5071278339747262059

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

๋„ค์ดํ‹ฐ๋ธŒ disabled ์†์„ฑ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฒ„ํŠผ์ด ํƒญ ์ด๋™ ์ˆœ์„œ์—์„œ ์ œ์™ธ๋˜์–ด, ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ ์‹œ ํ™”๋ฉด ํŒ๋…๊ธฐ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋œ ์ด์œ (ํˆดํŒ ๋“ฑ)๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์šด ์ ‘๊ทผ์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด:

  • ์ €์žฅ ๋ฒ„ํŠผ์˜ disabled ์†์„ฑ ๋Œ€์‹  aria-disabled="true"๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ ํฌ์ปค์Šค ๊ฐ€๋Šฅ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฒ„ํŠผ์ด aria-disabled="true"์ธ ์ƒํƒœ์—์„œ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ ํผ์ด ์ œ์ถœ๋  ๋•Œ, ๋„ค์ดํ‹ฐ๋ธŒ HTML5 ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํŒ์—…์ด ๋œจ๊ฑฐ๋‚˜ ์•ก์…˜์ด ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก click ๋ฐ submit ์ด๋ฒคํŠธ์— ๋ฐฉ์–ด ๋กœ์ง(event.preventDefault())์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • E2E ํ…Œ์ŠคํŠธ์—์„œ ๋ฐœ์ƒํ•˜๋˜ modulepreload ๋ˆ„๋ฝ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • .jules/palette.md ํŒŒ์ผ์— ์ ‘๊ทผ์„ฑ ๊ฐœ์„ ์— ๋Œ€ํ•œ ๋ฐฐ์›€์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค.

PR created automatically by Jules for task 5071278339747262059 started by @seonghobae


Open in Devin Review

โ€ฆtton

๋„ค์ดํ‹ฐ๋ธŒ `disabled` ์†์„ฑ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฒ„ํŠผ์ด ํƒญ ์ด๋™ ์ˆœ์„œ์—์„œ ์ œ์™ธ๋˜์–ด, ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ ์‹œ ํ™”๋ฉด ํŒ๋…๊ธฐ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋œ ์ด์œ (ํˆดํŒ ๋“ฑ)๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์šด ์ ‘๊ทผ์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์ €๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์—…ํ–ˆ์Šต๋‹ˆ๋‹ค:
- ์ €์žฅ ๋ฒ„ํŠผ์˜ `disabled` ์†์„ฑ ๋Œ€์‹  `aria-disabled="true"`๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ ํฌ์ปค์Šค ๊ฐ€๋Šฅ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค.
- ๋ฒ„ํŠผ์ด `aria-disabled="true"`์ธ ์ƒํƒœ์—์„œ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ ํผ์ด ์ œ์ถœ๋  ๋•Œ, ๋„ค์ดํ‹ฐ๋ธŒ HTML5 ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํŒ์—…์ด ๋œจ๊ฑฐ๋‚˜ ์•ก์…˜์ด ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํด๋ฆญ ๋ฐ ํผ ์ „์†ก ์ด๋ฒคํŠธ์— ๋ฐฉ์–ด ๋กœ์ง(`event.preventDefault()`)์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
- E2E ํ…Œ์ŠคํŠธ์—์„œ ๋ฐœ์ƒํ•˜๋˜ `modulepreload` ๋ˆ„๋ฝ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
- `.jules/palette.md` ํŒŒ์ผ์— ์ด๋ฒˆ ์ ‘๊ทผ์„ฑ ๊ฐœ์„ ์„ ํ†ตํ•ด ์–ป์€ ๋ฐฐ์›€์„ ๊ธฐ๋กํ•ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.
@google-labs-jules

Copy link
Copy Markdown

๐Ÿ‘‹ Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a ๐Ÿ‘€ emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Limit details: Youโ€™ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 80cb37fe-5970-407c-8b89-ce500b3a60b0

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 2c32887 and dc9d16f.

๐Ÿ“’ Files selected for processing (3)
  • .jules/palette.md
  • app.js
  • index.html

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread app.js
Comment on lines +404 to +408
const saveButton = event.target.closest('button[type="submit"]');
if (saveButton && saveButton.getAttribute('aria-disabled') === 'true') {
event.preventDefault();
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐ŸŸก Native browser validation popup still appears when clicking the disabled save button

The guard meant to swallow clicks on the disabled save button (event.target.closest('button[type="submit"]') at app.js:404-408) is placed after an early return that only continues for rows carrying a task id, but the editor form sits in a row without one, so the guard never runs and the browser's native validation bubble pops up on click.
Impact: A user who clicks the greyed-out save button while required fields are invalid sees the native browser validation popup, the exact jarring behavior this change set out to eliminate.

Why the click guard is unreachable

The click listener starts with const row = event.target.closest('tr[data-task-id]'); if (!row) return; (app.js:387-390). The editor form is rendered inside renderEditorRow, whose <tr> gets row.dataset.editorAnchor = anchorId (app.js:797) and is a sibling of task rows, not a descendant. Task rows are the only ones with data-task-id (app.js:687). Therefore, when the save button is clicked, closest('tr[data-task-id]') returns null, the handler returns at line 389, and the new block at app.js:404-408 never executes. Because the click's default action is not prevented, the browser runs constraint validation for required fields (set at app.js:887) and shows the native popup before any submit event is dispatched. The submit-event guard at app.js:439-442 cannot help here because constraint-validation failure suppresses the submit event entirely. Previously the native disabled attribute made the click a no-op, so this is a regression against the PR's goal.

Prompt for agents
The click guard added in bindTableEvents (app.js:404-408) that calls event.preventDefault() when the submit button has aria-disabled="true" is never reached. The tableBody click handler returns early at app.js:387-390 whenever event.target has no ancestor tr[data-task-id]. The editor form's row is created in renderEditorRow with row.dataset.editorAnchor (app.js:797) and has no data-task-id, so clicks on the save button hit the early return before reaching the guard. As a result, clicking the aria-disabled save button is not prevented at the click level, and the browser's native constraint-validation popup (for required fields set at app.js:887) still appears โ€” defeating the purpose of the change. Fix by relocating the save-button aria-disabled check to run before the `if (!row) return` early return at the top of the click handler (or otherwise ensure the guard executes for clicks originating inside the editor row), so event.preventDefault() is called on the click before the browser attempts form submission.
Open in Devin Review

Was this helpful? React with ๐Ÿ‘ or ๐Ÿ‘Ž to provide feedback.

Copy link
Copy Markdown
Contributor Author

Closing as superseded by the existing canonical editor-validation lane #468 after exact semantic comparison against current develop.

The overlap is complete for the valuable buyer surface (aria-disabled save semantics and restored modulepreload entries), while #468 additionally preserves the actual persistence authority with synchronous latest-draft validation, aria-describedby, focused browser regression coverage, and the related CSV hardening. This PR's new click guard is also currently unreachable for the editor row because the table click handler returns before reaching it when there is no tr[data-task-id], as the current Devin review correctly identifies. Its submit guard additionally relies on the presentation-time aria-disabled state rather than the latest-draft validation boundary, so adopting it would reintroduce the stale-debounce failure that #468 was created to remove.

No unique product behavior from this branch needs to be preserved separately. The .jules/palette.md note is non-authoritative agent learning, not a production requirement. Please continue the accessibility fix through #468 rather than maintaining a competing branch.

@seonghobae seonghobae closed this Aug 21, 2026
@google-labs-jules

Copy link
Copy Markdown

Closing as superseded by the existing canonical editor-validation lane #468 after exact semantic comparison against current develop.

The overlap is complete for the valuable buyer surface (aria-disabled save semantics and restored modulepreload entries), while #468 additionally preserves the actual persistence authority with synchronous latest-draft validation, aria-describedby, focused browser regression coverage, and the related CSV hardening. This PR's new click guard is also currently unreachable for the editor row because the table click handler returns before reaching it when there is no tr[data-task-id], as the current Devin review correctly identifies. Its submit guard additionally relies on the presentation-time aria-disabled state rather than the latest-draft validation boundary, so adopting it would reintroduce the stale-debounce failure that #468 was created to remove.

No unique product behavior from this branch needs to be preserved separately. The .jules/palette.md note is non-authoritative agent learning, not a production requirement. Please continue the accessibility fix through #468 rather than maintaining a competing branch.

Understood. Acknowledging that this work is superseded by #468 and stopping work on this task. I will not push any further updates to this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant