Skip to content

🎨 Palette: Improve accessibility of coverage filters and search#201

Draft
EffortlessSteven wants to merge 1 commit intomainfrom
palette-a11y-coverage-7337919575116934754
Draft

🎨 Palette: Improve accessibility of coverage filters and search#201
EffortlessSteven wants to merge 1 commit intomainfrom
palette-a11y-coverage-7337919575116934754

Conversation

@EffortlessSteven
Copy link
Member

This PR improves the accessibility of the AC Coverage page by adding ARIA attributes to interactive elements. It also fixes a bug where inline JavaScript and CSS were being incorrectly escaped by the maud template engine, breaking the filtering functionality.

Changes:

  • Modified crates/http-platform/src/ui.rs:
    • Added aria-label to search input.
    • Added aria-pressed and aria-controls to filter buttons.
    • Wrapped inline JS and CSS in PreEscaped to prevent HTML entity escaping.
    • Updated JS to toggle aria-pressed.
  • Modified crates/app-http/tests/ui_contract_dom.rs:
    • Added test_coverage_page_accessibility to verify the presence and correctness of new attributes.

Verification:

  • Ran cargo test -p app-http (new test passed).
  • Verified frontend functionality and accessibility attributes using a Playwright script (screenshot generated).

PR created automatically by Jules for task 7337919575116934754 started by @EffortlessSteven

- Add `aria-label` to coverage search input.
- Add `aria-pressed` and `aria-controls` to coverage filter buttons.
- Update embedded JavaScript to toggle `aria-pressed` state on click.
- Fix `maud` escaping issue by wrapping inline scripts and styles in `PreEscaped`.
- Add integration test `test_coverage_page_accessibility` to verify attributes.

Accessibility improvements:
- Screen readers can now identify the purpose of the search box.
- Screen readers can now determine which filter is currently active.

Bug fix:
- Inline JavaScript `&&` operator was previously escaped to `&&`, breaking the filter logic. This is now fixed using `PreEscaped`.
Copilot AI review requested due to automatic review settings February 15, 2026 02:39
@google-labs-jules
Copy link

👋 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
Copy link

coderabbitai bot commented Feb 15, 2026

Summary by CodeRabbit

  • Documentation

    • Added guidance on proper handling of inline scripts and CSS content to prevent unintended escaping.
  • Tests

    • Added comprehensive accessibility tests for the coverage page filtering interface.
  • Bug Fixes

    • Fixed escaping behavior for inline CSS and JavaScript content in rendered pages.
    • Improved search and filter accessibility by adding proper ARIA labels and state indicators.

Walkthrough

Added documentation about Maud HTML escaping behavior, introduced accessibility tests for coverage page UI elements, and updated UI rendering code to wrap dynamic HTML/CSS/JavaScript content with PreEscaped() while adding ARIA attributes to interactive controls for improved screen reader support.

Changes

Cohort / File(s) Summary
Documentation
.Jules/palette.md
Added section documenting Maud's string escaping behavior and guidance to wrap inline CSS/JS content in PreEscaped(...) to prevent unwanted escaping.
Accessibility Tests
crates/app-http/tests/ui_contract_dom.rs
Added test function verifying coverage page accessibility attributes: search input aria-label, filter button aria-pressed and aria-controls attributes, and initial button states.
UI Rendering & Accessibility
crates/http-platform/src/ui.rs
Updated HTML fragment generation to wrap dynamic content (mermaid diagrams, inline styles, inline scripts) with PreEscaped() to prevent escaping; added ARIA attributes (aria-pressed, aria-controls, aria-label) to coverage filter controls and updated scripts to manage ARIA state on user interaction.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 In code where HTML takes its form,
We escape with care, then transform!
With ARIA whispers, labels true,
Accessible pages shine brand new,
PreEscaped shields our script so bright.


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

@gemini-code-assist
Copy link

Summary of Changes

Hello @EffortlessSteven, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the user experience on the AC Coverage page by addressing critical accessibility concerns and fixing a rendering bug. By integrating ARIA attributes, interactive elements are now more usable for all users, including those relying on assistive technologies. The fix for maud's escaping behavior ensures that dynamic content, such as filtering, functions as intended, restoring full functionality to the page.

Highlights

  • Accessibility Improvements: Enhanced the accessibility of the AC Coverage page by adding aria-label to the search input and aria-pressed and aria-controls attributes to filter buttons, improving navigation and interaction for assistive technologies.
  • Maud Template Engine Bug Fix: Resolved an issue where the maud template engine was incorrectly escaping inline JavaScript and CSS, which previously broke filtering functionality. This was fixed by wrapping inline scripts, styles, and pre-formatted content in PreEscaped.
  • New UI Contract Test: Introduced a new UI contract test, test_coverage_page_accessibility, to verify the correct implementation and presence of the new ARIA attributes on the coverage page, ensuring ongoing accessibility compliance.
Changelog
  • .Jules/palette.md
    • Added a new learning note documenting the maud template engine's behavior of escaping inline scripts and styles, and the solution using PreEscaped.
  • crates/app-http/tests/ui_contract_dom.rs
    • Added a new asynchronous test, test_coverage_page_accessibility, to verify the presence and correctness of ARIA attributes on the coverage page's search box and filter buttons.
  • crates/http-platform/src/ui.rs
    • Imported the PreEscaped type from the maud crate.
    • Wrapped mermaid_diagram content in PreEscaped to prevent incorrect HTML escaping.
    • Wrapped inline style and script blocks in PreEscaped to ensure correct rendering of CSS and JavaScript.
    • Applied PreEscaped to coverage_styles() and coverage_script() calls within the coverage_content() function.
    • Added aria-pressed and aria-controls attributes to filter buttons and aria-label to the search input for improved accessibility.
    • Modified the coverage_script() JavaScript function to dynamically update the aria-pressed attribute on filter buttons when their state changes.
Activity
  • The pull request was automatically created by Jules for task 7337919575116934754, initiated by @EffortlessSteven.
  • The author verified the changes by running cargo test -p app-http, confirming the new test passed.
  • Frontend functionality and accessibility attributes were verified using a Playwright script, and a screenshot was generated to confirm the visual and functional correctness.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively improves the accessibility of the coverage page by adding appropriate ARIA attributes and fixes an HTML escaping issue with inline scripts and styles in the maud templates. The changes are well-supported by a new accessibility test, and a suggestion has been made to make the new test more comprehensive.

Comment on lines +335 to +344
// Verify 'All' button is pressed by default
let all_btn_selector = Selector::parse("button#filter-all").unwrap();
let all_btn = document.select(&all_btn_selector).next().unwrap();
assert_eq!(all_btn.value().attr("aria-pressed"), Some("true"));

// Verify 'Passing' button is not pressed
let passing_btn_selector = Selector::parse("button#filter-passing").unwrap();
let passing_btn = document.select(&passing_btn_selector).next().unwrap();
assert_eq!(passing_btn.value().attr("aria-pressed"), Some("false"));
}

Choose a reason for hiding this comment

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

medium

The test currently only verifies the initial aria-pressed state for the 'All' and 'Passing' filter buttons. To make the test more robust and comprehensive, it would be better to check the initial state of all filter buttons ('failing' and 'unknown' as well).

Refactoring this into a loop would also make the test more maintainable if more filters are added in the future.

    // Verify initial aria-pressed states
    for (filter_id, expected_state) in [
        ("all", "true"),
        ("passing", "false"),
        ("failing", "false"),
        ("unknown", "false"),
    ] {
        let selector_str = format!("button#filter-{}", filter_id);
        let selector = Selector::parse(&selector_str).unwrap();
        let button = document.select(&selector).next().unwrap_or_else(|| {
            panic!("Filter button with selector '{}' not found", selector_str)
        });
        assert_eq!(
            button.value().attr("aria-pressed"),
            Some(expected_state),
            "Button '{}' should have aria-pressed='{}'",
            filter_id,
            expected_state
        );
    }
}

Copy link

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

Improves accessibility and restores correct client-side behavior on the AC Coverage UI by adding ARIA attributes to filter/search controls and preventing maud from HTML-escaping inline CSS/JS content (which breaks rawtext/script contexts).

Changes:

  • Wrap inline <style>/<script> content in PreEscaped(...) to avoid entity escaping that breaks CSS/JS.
  • Add aria-label to the coverage search input and aria-pressed/aria-controls to filter buttons; update JS to toggle aria-pressed.
  • Add a DOM contract test verifying the new accessibility attributes on /ui/coverage.

Reviewed changes

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

File Description
crates/http-platform/src/ui.rs Adds ARIA attributes to coverage controls and uses PreEscaped for inline CSS/JS (and Mermaid output).
crates/app-http/tests/ui_contract_dom.rs Adds an accessibility-focused DOM test for the coverage page.
.Jules/palette.md Documents the PreEscaped requirement for inline CSS/JS and Mermaid content in maud.

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

}
.mermaid data-uiid="graph.diagram" {
(mermaid_diagram)
(PreEscaped(mermaid_diagram))
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

PreEscaped(mermaid_diagram) renders the Mermaid source as raw HTML. Since graph.to_mermaid() incorporates labels from specs and mermaid_label() only escapes quotes (not <, >, &), a crafted title/label containing <...> could be interpreted as HTML and become an XSS/injection vector (or simply break the page markup). Prefer emitting the diagram as normal escaped text (no PreEscaped) if Mermaid can parse via textContent, or otherwise ensure the diagram is inserted in a way that cannot be HTML-parsed (e.g., via textContent) / is properly sanitized before PreEscaped.

Suggested change
(PreEscaped(mermaid_diagram))
(mermaid_diagram)

Copilot uses AI. Check for mistakes.

## 2026-02-15 - Maud Escaping Inline Scripts/Styles
**Learning:** `maud` automatically escapes string content, which breaks inline JavaScript (e.g., `&&` becomes `&amp;&amp;`) and CSS (e.g., `>` becomes `&gt;`).
**Action:** Always wrap inline CSS, JavaScript, and pre-formatted content (like Mermaid diagrams) in `PreEscaped(...)` when using `maud` templates.
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The guidance to "Always wrap ... pre-formatted content (like Mermaid diagrams) in PreEscaped(...)" is overly broad. PreEscaped disables HTML escaping and is only safe for trusted/static content; for dynamic content derived from specs/user input it can introduce XSS or markup-breaking injection. Consider updating this note to distinguish inline <style>/<script> (where escaping breaks functionality) from dynamic HTML/text content (where PreEscaped should be avoided or combined with sanitization / textContent insertion).

Suggested change
**Action:** Always wrap inline CSS, JavaScript, and pre-formatted content (like Mermaid diagrams) in `PreEscaped(...)` when using `maud` templates.
**Action:** For trusted/static inline CSS or JavaScript where escaping breaks functionality, wrap the block in `PreEscaped(...)`. Do not use `PreEscaped` for dynamic or user-controlled content (including pre-formatted text like Mermaid diagrams); instead, let `maud` escape it, sanitize it first, or inject it via safe mechanisms (e.g., `textContent` in JS).

Copilot uses AI. Check for mistakes.
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