Skip to content

🎨 Palette: Improve Search Empty States & Accessibility#103

Open
SlasshyOverhere wants to merge 1 commit into
mainfrom
jules-palette-ux-empty-state-13279054375330315754
Open

🎨 Palette: Improve Search Empty States & Accessibility#103
SlasshyOverhere wants to merge 1 commit into
mainfrom
jules-palette-ux-empty-state-13279054375330315754

Conversation

@SlasshyOverhere
Copy link
Copy Markdown
Owner

@SlasshyOverhere SlasshyOverhere commented Apr 6, 2026

This commit introduces micro-UX improvements to the BlankDrive Web UI to enhance accessibility and the empty state experience.

What was added:

  • Added aria-live="polite" attributes to dynamic areas (#entryList and #detailHint) so screen readers get state updates.
  • Rendered a "Clear Filters" button on empty search results so users don't have to manually delete their query to recover their view.
  • Added a keyboard listener for the Escape key on the search input to quickly clear and unfocus it.

Why:

  • Accessibility relies on announcing dynamic DOM updates; without aria-live, users relying on screen readers wouldn't know when their search yielded zero results.
  • An empty screen without an action path when a filter is applied creates friction; a single-click reset clears this up.
  • Fast keyboard navigation is critical for power users traversing large vaults.

PR created automatically by Jules for task 13279054375330315754 started by @SlasshyOverhere

Summary by CodeRabbit

  • New Features

    • Added keyboard shortcut: press Escape to clear search input and reset focus.
    • Added "Clear Filters" button to empty state for quick recovery when using search or type filters.
  • Documentation

    • Documented accessibility improvements for search-driven empty states.
  • Accessibility

    • Enhanced assistive technology support with live region announcements for search and filter changes.

- Add `aria-live="polite"` to `#entryList` and `#detailHint` to ensure screen readers announce dynamic text changes without page reloads.
- Introduce an actionable "Clear Filters" button in the empty state when search filters yield no results, preventing dead-end UI states.
- Add an `Escape` keyboard shortcut to clear search and type filters quickly via keyboard.
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 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.

Copilot AI review requested due to automatic review settings April 6, 2026 16:08
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 6, 2026

📝 Walkthrough

Walkthrough

This PR enhances web UI accessibility by introducing ARIA live region announcements for dynamic list updates, adding a clear filters button in empty states when search/filters are active, and implementing an Escape key shortcut to clear the search input.

Changes

Cohort / File(s) Summary
Documentation
.jules/palette.md
Added accessibility guideline entry documenting best practices for search-driven empty states: using aria-live="polite" for list updates and providing explicit recovery actions (e.g., "Clear Filters" button).
Web UI Template
src/webui/template.ts
Updated entry sidebar list and detail hint paragraph with aria-live="polite" for assistive technology announcements. Enhanced renderEntries() empty-state logic to conditionally render a "Clear Filters" button when filters are active, resetting search and type filter values. Added Escape key handler on search input to clear search, blur input, and refresh entries.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A whisper to screen readers clear,
"Live regions now, your voice they hear!"
When filters blur the list so bright,
A "Clear" button makes it right.
Press Escape, and search takes flight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: accessibility improvements (aria-live) and search empty state UX enhancements (Clear Filters button and keyboard shortcuts).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jules-palette-ux-empty-state-13279054375330315754

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 and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the BlankDrive Web UI template to improve accessibility announcements for dynamic UI regions and to make “no search results” states easier to recover from.

Changes:

  • Added aria-live="polite" to the entry list and detail hint regions to announce client-side state changes to screen readers.
  • Enhanced the “no entries” empty state to show a “Clear Filters” action when the view is filtered.
  • Added an Escape key handler on the search input to clear and unfocus the search box.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/webui/template.ts Adds aria-live, improves filtered empty state UX (Clear Filters), and introduces Escape-to-clear behavior on search.
.jules/palette.md Updates internal Jules palette notes with guidance about these UX/accessibility changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/webui/template.ts
if(!s.entries.length){
const li=document.createElement('li');
li.className='hint empty-state';
const isFiltered = !!el.search.value || el.typeFilter.value !== 'all';
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

isFiltered treats whitespace in the search box as an active filter (!!el.search.value), but entryFilters() trims the query before sending it. This can produce a confusing empty-state message ("No entries match…") even when the effective query is empty. Use the same trimmed logic as entryFilters() when computing isFiltered.

Suggested change
const isFiltered = !!el.search.value || el.typeFilter.value !== 'all';
const isFiltered = !!el.search.value.trim() || el.typeFilter.value !== 'all';

Copilot uses AI. Check for mistakes.
Comment thread src/webui/template.ts
Comment on lines +1028 to +1029
clearBtn.className = 'btn outline';
clearBtn.style.marginTop = '10px';
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The new Clear Filters button uses className = 'btn outline', but the stylesheet in this template defines btn-primary, btn-ghost, btn-danger, etc., and does not define btn/outline. As a result this button likely won't match existing button styling. Reuse an existing button class (e.g., btn-ghost) or add matching CSS for the new classes; also consider avoiding the inline style.marginTop in favor of a CSS rule.

Suggested change
clearBtn.className = 'btn outline';
clearBtn.style.marginTop = '10px';
clearBtn.className = 'btn-ghost';

Copilot uses AI. Check for mistakes.
Comment thread src/webui/template.ts
el.search.addEventListener('keydown',(e)=>{
if(e.key==='Escape') {
el.search.value='';
el.search.blur();
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The Escape handler triggers an immediate refreshEntries() but does not cancel any pending debounced refresh from the input handler (searchTimer). If the user presses Escape soon after typing, this can cause back-to-back network requests. Clear any pending searchTimer (and reset it) before calling refreshEntries() here.

Suggested change
el.search.blur();
el.search.blur();
if(searchTimer){clearTimeout(searchTimer);searchTimer=null}

Copilot uses AI. Check for mistakes.
Comment thread .jules/palette.md
Comment on lines +20 to +22
## 2026-04-06 - Improve Accessibility and Usability of Search Empty States
**Learning:** For text-based UI updates in single-page apps (like toggling an empty state list item), explicitly applying `aria-live="polite"` ensures screen readers announce the changes, which is critical since they happen client-side without a page reload. Additionally, empty states that result from a filtered view (like search) should always provide an actionable UI path to reset the view (e.g., a "Clear Filters" button), rather than forcing the user to manually clear their inputs to recover.
**Action:** When creating text updates for dynamically rendered lists, always add `aria-live` to the list container. Always combine empty states for filtered lists with an explicit reset action like a button or shortcut hint.
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

Repo convention is to avoid committing generated/internal .jules/* artifacts in merged PRs (see CHANGELOG.md noting their removal). This file update should be excluded from the PR or moved to a non-internal docs location if it needs to be kept.

Suggested change
## 2026-04-06 - Improve Accessibility and Usability of Search Empty States
**Learning:** For text-based UI updates in single-page apps (like toggling an empty state list item), explicitly applying `aria-live="polite"` ensures screen readers announce the changes, which is critical since they happen client-side without a page reload. Additionally, empty states that result from a filtered view (like search) should always provide an actionable UI path to reset the view (e.g., a "Clear Filters" button), rather than forcing the user to manually clear their inputs to recover.
**Action:** When creating text updates for dynamically rendered lists, always add `aria-live` to the list container. Always combine empty states for filtered lists with an explicit reset action like a button or shortcut hint.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/webui/template.ts (1)

1103-1109: Avoid duplicate refreshes on Escape in search.

On Line 1104+, Escape should clear any pending debounce and prevent native/default Escape behavior to avoid extra refreshEntries() calls.

💡 Suggested fix
     el.search.addEventListener('keydown',(e)=>{
       if(e.key==='Escape') {
+        e.preventDefault();
+        if(searchTimer) clearTimeout(searchTimer);
         el.search.value='';
         el.search.blur();
         void refreshEntries();
       }
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/webui/template.ts` around lines 1103 - 1109, Escape handling on the
search input currently clears the value and calls refreshEntries but can trigger
duplicate refreshes due to pending debounce or native Escape behavior; update
the el.search keydown handler to call e.preventDefault() and
e.stopPropagation(), cancel/clear any pending search debounce (e.g.,
clearTimeout(searchDebounceTimer) or call the debounce cancellation helper used
for the search), then clear el.search.value, blur the input, and call
refreshEntries() once so no duplicate refreshes occur. Ensure you update the
handler attached via el.search.addEventListener and reference the existing
debounce cancellation symbol used in this module (or create one if missing).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/webui/template.ts`:
- Around line 1026-1030: The Clear Filters button uses a non-existent variant
class "btn outline" causing styling drift; update the className on the clearBtn
element to use an existing button variant defined in this file (e.g., the same
class string used by other buttons like the primary/secondary/outline variant in
this template) so it inherits the dark-theme styles — locate the clearBtn
creation (variable clearBtn) and replace its className assignment with the
canonical button class used elsewhere in this module.

---

Nitpick comments:
In `@src/webui/template.ts`:
- Around line 1103-1109: Escape handling on the search input currently clears
the value and calls refreshEntries but can trigger duplicate refreshes due to
pending debounce or native Escape behavior; update the el.search keydown handler
to call e.preventDefault() and e.stopPropagation(), cancel/clear any pending
search debounce (e.g., clearTimeout(searchDebounceTimer) or call the debounce
cancellation helper used for the search), then clear el.search.value, blur the
input, and call refreshEntries() once so no duplicate refreshes occur. Ensure
you update the handler attached via el.search.addEventListener and reference the
existing debounce cancellation symbol used in this module (or create one if
missing).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8c2c73ff-7563-4556-8131-479c1ddb9132

📥 Commits

Reviewing files that changed from the base of the PR and between 1cdcca9 and 4db91c8.

📒 Files selected for processing (2)
  • .jules/palette.md
  • src/webui/template.ts

Comment thread src/webui/template.ts
Comment on lines +1026 to +1030
const clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.className = 'btn outline';
clearBtn.style.marginTop = '10px';
clearBtn.textContent = 'Clear Filters';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use an existing button variant for “Clear Filters.”

On Line 1028, btn outline doesn’t map to styles defined in this file, so the control may render with inconsistent/default browser styling in the dark theme.

💡 Suggested fix
-          clearBtn.className = 'btn outline';
+          clearBtn.className = 'btn-ghost btn-sm';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.className = 'btn outline';
clearBtn.style.marginTop = '10px';
clearBtn.textContent = 'Clear Filters';
const clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.className = 'btn-ghost btn-sm';
clearBtn.style.marginTop = '10px';
clearBtn.textContent = 'Clear Filters';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/webui/template.ts` around lines 1026 - 1030, The Clear Filters button
uses a non-existent variant class "btn outline" causing styling drift; update
the className on the clearBtn element to use an existing button variant defined
in this file (e.g., the same class string used by other buttons like the
primary/secondary/outline variant in this template) so it inherits the
dark-theme styles — locate the clearBtn creation (variable clearBtn) and replace
its className assignment with the canonical button class used elsewhere in this
module.

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.

2 participants