Skip to content

Conversation

@sfc-gh-bnisco
Copy link
Collaborator

@sfc-gh-bnisco sfc-gh-bnisco commented Dec 16, 2025

Describe your changes

  • Improves keyboard accessibility for heading anchor links by:
    • Making anchor icons keyboard focusable and visible on focus (not just hover).
    • Adding proper ARIA attributes to headings with action elements.
    • Adding a tab_until_focused utility for more resilient keyboard navigation e2e tests.
    • Ensuring Escape key properly dismisses tooltips when focus-triggered.
    • Adding focus styles to links in markdown content

Screenshot or video (only for visual changes)

In this video I am tabbing through the Markdown header links. I use the enter key once and I use shift-tab to go backwards as well:

Kapture.2025-12-16.at.15.13.56.mp4

GitHub Issue Link (if applicable)

Testing Plan

  • ✅ Adds unit tests
  • ✅ Adds e2e tests

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

@snyk-io
Copy link
Contributor

snyk-io bot commented Dec 16, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@sfc-gh-bnisco sfc-gh-bnisco added change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users security-assessment-completed Security assessment has been completed for PR labels Dec 16, 2025 — with Graphite App
@github-actions
Copy link
Contributor

github-actions bot commented Dec 16, 2025

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13378/streamlit-1.52.1-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13378.streamlit.app (☁️ Deploy here if not accessible)

Copy link
Collaborator Author

sfc-gh-bnisco commented Dec 16, 2025

@sfc-gh-bnisco sfc-gh-bnisco added change:bugfix PR contains bug fix implementation and removed change:feature PR contains new feature or enhancement implementation labels Dec 16, 2025
Copy link
Contributor

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 fixes keyboard accessibility for anchor links in Markdown headers (#13329) by ensuring the link icons are reachable via keyboard navigation. The key changes involve switching from visibility to opacity for hiding anchor icons (keeping them in tab order) and adding proper ARIA labels for accessibility.

Key Changes

  • Modified CSS to use opacity: 0 instead of visibility: hidden for anchor link icons, keeping them keyboard-accessible
  • Added aria-label "Link to heading" to anchor links for screen reader support
  • Implemented aria-labelledby pattern to maintain stable heading names when containing interactive elements
  • Added Escape key handler for tooltips to improve keyboard navigation
  • Created tab_until_focused E2E test utility for robust keyboard navigation testing

Reviewed changes

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

Show a summary per file
File Description
frontend/lib/src/components/shared/Tooltip/Tooltip.tsx Added Escape key handler to close focus-triggered tooltips
frontend/lib/src/components/shared/StreamlitMarkdown/StreamlitMarkdown.tsx Added aria-label to anchor links, aria-labelledby to headings, and aria-hidden/focusable to icon SVG
frontend/lib/src/components/shared/StreamlitMarkdown/Heading.test.tsx Updated test to verify accessible name of anchor links
e2e_playwright/st_markdown_test.py Added E2E test for keyboard focus on markdown heading anchor icons
e2e_playwright/st_heading_test.py Added E2E test for keyboard focus and updated CSS assertions (opacity vs visibility)
e2e_playwright/shared/app_utils.py Added tab_until_focused utility function for resilient keyboard navigation testing
e2e_playwright/__snapshots__/linux/st_heading_test/*.png Updated snapshots to reflect visual changes from CSS modifications

@github-actions
Copy link
Contributor

github-actions bot commented Dec 16, 2025

📉 Frontend coverage change detected

The frontend unit test (vitest) coverage has decreased by 0.0000%

  • Current PR: 86.3500% (12622 lines, 1722 missed)
  • Latest develop: 86.3500% (12618 lines, 1722 missed)

✅ Coverage change is within normal range.

📊 View detailed coverage comparison

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 8058013 to 8eeeed6 Compare December 16, 2025 05:06
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown branch from 096a34d to 5678480 Compare December 16, 2025 05:06
Copy link
Contributor

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

Copilot reviewed 8 out of 14 changed files in this pull request and generated 1 comment.

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 8eeeed6 to 92962c4 Compare December 16, 2025 16:49
Copy link
Contributor

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

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

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 92962c4 to 8f4981c Compare December 16, 2025 23:14
Copy link
Contributor

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

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

@github-actions
Copy link
Contributor

github-actions bot commented Dec 16, 2025

📉 Python coverage change detected

The Python unit test coverage has decreased by 0.0048%

  • Current PR: 92.7910% (20960 statements, 1511 missed)
  • Latest develop: 92.7958% (20960 statements, 1510 missed)

✅ Coverage change is within normal range.

Coverage by files
Name Stmts Miss Cover
streamlit/__init__.py 142 0 100%
streamlit/__main__.py 3 3 0%
streamlit/auth_util.py 100 25 75%
streamlit/cli_util.py 39 6 85%
streamlit/column_config.py 3 0 100%
streamlit/commands/__init__.py 0 0 100%
streamlit/commands/echo.py 54 11 80%
streamlit/commands/execution_control.py 70 10 86%
streamlit/commands/experimental_query_params.py 40 2 95%
streamlit/commands/logo.py 41 6 85%
streamlit/commands/navigation.py 106 2 98%
streamlit/commands/page_config.py 106 4 96%
streamlit/components/__init__.py 0 0 100%
streamlit/components/lib/__init__.py 0 0 100%
streamlit/components/lib/local_component_registry.py 35 2 94%
streamlit/components/types/__init__.py 0 0 100%
streamlit/components/types/base_component_registry.py 14 0 100%
streamlit/components/types/base_custom_component.py 49 6 88%
streamlit/components/v1/__init__.py 5 0 100%
streamlit/components/v1/component_arrow.py 33 8 76%
streamlit/components/v1/component_registry.py 41 3 93%
streamlit/components/v1/components.py 4 4 0%
streamlit/components/v1/custom_component.py 85 7 92%
streamlit/components/v2/__init__.py 24 0 100%
streamlit/components/v2/bidi_component/__init__.py 4 0 100%
streamlit/components/v2/bidi_component/constants.py 5 0 100%
streamlit/components/v2/bidi_component/main.py 152 17 89%
streamlit/components/v2/bidi_component/serialization.py 81 2 98%
streamlit/components/v2/bidi_component/state.py 13 0 100%
streamlit/components/v2/component_definition_resolver.py 30 0 100%
streamlit/components/v2/component_file_watcher.py 117 9 92%
streamlit/components/v2/component_manager.py 97 13 87%
streamlit/components/v2/component_manifest_handler.py 24 0 100%
streamlit/components/v2/component_path_utils.py 68 5 93%
streamlit/components/v2/component_registry.py 121 8 93%
streamlit/components/v2/get_bidi_component_manager.py 8 1 88%
streamlit/components/v2/manifest_scanner.py 224 25 89%
streamlit/components/v2/presentation.py 84 19 77%
streamlit/components/v2/types.py 8 8 0%
streamlit/config.py 412 12 97%
streamlit/config_option.py 79 3 96%
streamlit/config_util.py 288 7 98%
streamlit/connections/__init__.py 6 0 100%
streamlit/connections/base_connection.py 45 0 100%
streamlit/connections/snowflake_connection.py 60 13 78%
streamlit/connections/snowpark_connection.py 44 3 93%
streamlit/connections/sql_connection.py 56 6 89%
streamlit/connections/util.py 33 0 100%
streamlit/cursor.py 130 1 99%
streamlit/dataframe_util.py 501 47 91%
streamlit/delta_generator.py 250 7 97%
streamlit/delta_generator_singletons.py 74 7 91%
streamlit/deprecation_util.py 59 4 93%
streamlit/development.py 1 0 100%
streamlit/elements/__init__.py 0 0 100%
streamlit/elements/alert.py 60 0 100%
streamlit/elements/arrow.py 201 15 93%
streamlit/elements/balloons.py 10 0 100%
streamlit/elements/bokeh_chart.py 9 0 100%
streamlit/elements/code.py 20 1 95%
streamlit/elements/deck_gl_json_chart.py 104 10 90%
streamlit/elements/dialog_decorator.py 38 0 100%
streamlit/elements/doc_string.py 227 9 96%
streamlit/elements/empty.py 16 4 75%
streamlit/elements/exception.py 101 10 90%
streamlit/elements/form.py 56 2 96%
streamlit/elements/graphviz_chart.py 35 1 97%
streamlit/elements/heading.py 56 0 100%
streamlit/elements/html.py 49 0 100%
streamlit/elements/iframe.py 29 0 100%
streamlit/elements/image.py 32 0 100%
streamlit/elements/json.py 39 2 95%
streamlit/elements/layouts.py 140 3 98%
streamlit/elements/lib/__init__.py 0 0 100%
streamlit/elements/lib/built_in_chart_utils.py 390 26 93%
streamlit/elements/lib/color_util.py 100 4 96%
streamlit/elements/lib/column_config_utils.py 169 1 99%
streamlit/elements/lib/column_types.py 189 4 98%
streamlit/elements/lib/dialog.py 69 1 99%
streamlit/elements/lib/dicttools.py 39 2 95%
streamlit/elements/lib/file_uploader_utils.py 30 0 100%
streamlit/elements/lib/form_utils.py 26 0 100%
streamlit/elements/lib/image_utils.py 176 21 88%
streamlit/elements/lib/js_number.py 28 3 89%
streamlit/elements/lib/layout_utils.py 121 1 99%
streamlit/elements/lib/mutable_status_container.py 73 4 95%
streamlit/elements/lib/options_selector_utils.py 90 0 100%
streamlit/elements/lib/pandas_styler_utils.py 80 2 98%
streamlit/elements/lib/policies.py 56 1 98%
streamlit/elements/lib/shortcut_utils.py 42 2 95%
streamlit/elements/lib/streamlit_plotly_theme.py 49 0 100%
streamlit/elements/lib/subtitle_utils.py 76 13 83%
streamlit/elements/lib/utils.py 76 5 93%
streamlit/elements/map.py 110 1 99%
streamlit/elements/markdown.py 65 2 97%
streamlit/elements/media.py 181 8 96%
streamlit/elements/metric.py 104 0 100%
streamlit/elements/pdf.py 49 2 96%
streamlit/elements/plotly_chart.py 129 6 95%
streamlit/elements/progress.py 36 0 100%
streamlit/elements/pyplot.py 39 2 95%
streamlit/elements/snow.py 10 0 100%
streamlit/elements/space.py 12 0 100%
streamlit/elements/spinner.py 44 3 93%
streamlit/elements/text.py 16 0 100%
streamlit/elements/toast.py 26 0 100%
streamlit/elements/vega_charts.py 228 3 99%
streamlit/elements/widgets/__init__.py 0 0 100%
streamlit/elements/widgets/audio_input.py 68 10 85%
streamlit/elements/widgets/button.py 245 6 98%
streamlit/elements/widgets/button_group.py 171 1 99%
streamlit/elements/widgets/camera_input.py 62 10 84%
streamlit/elements/widgets/chat.py 237 58 76%
streamlit/elements/widgets/checkbox.py 52 0 100%
streamlit/elements/widgets/color_picker.py 59 2 97%
streamlit/elements/widgets/data_editor.py 254 14 94%
streamlit/elements/widgets/file_uploader.py 108 18 83%
streamlit/elements/widgets/multiselect.py 105 4 96%
streamlit/elements/widgets/number_input.py 143 5 97%
streamlit/elements/widgets/radio.py 83 5 94%
streamlit/elements/widgets/select_slider.py 97 0 100%
streamlit/elements/widgets/selectbox.py 91 2 98%
streamlit/elements/widgets/slider.py 241 8 97%
streamlit/elements/widgets/text_widgets.py 130 6 95%
streamlit/elements/widgets/time_widgets.py 390 19 95%
streamlit/elements/write.py 166 32 81%
streamlit/emojis.py 4 0 100%
streamlit/env_util.py 21 3 86%
streamlit/error_util.py 33 2 94%
streamlit/errors.py 194 25 87%
streamlit/external/__init__.py 0 0 100%
streamlit/external/langchain/__init__.py 2 0 100%
streamlit/external/langchain/streamlit_callback_handler.py 141 82 42%
streamlit/file_util.py 84 8 90%
streamlit/git_util.py 100 5 95%
streamlit/logger.py 54 0 100%
streamlit/material_icon_names.py 1 0 100%
streamlit/navigation/__init__.py 0 0 100%
streamlit/navigation/page.py 78 2 97%
streamlit/net_util.py 55 3 95%
streamlit/platform.py 10 1 90%
streamlit/runtime/__init__.py 8 0 100%
streamlit/runtime/app_session.py 460 91 80%
streamlit/runtime/caching/__init__.py 19 0 100%
streamlit/runtime/caching/cache_data_api.py 171 3 98%
streamlit/runtime/caching/cache_errors.py 45 4 91%
streamlit/runtime/caching/cache_resource_api.py 132 1 99%
streamlit/runtime/caching/cache_type.py 11 1 91%
streamlit/runtime/caching/cache_utils.py 165 9 95%
streamlit/runtime/caching/cached_message_replay.py 108 1 99%
streamlit/runtime/caching/hashing.py 311 25 92%
streamlit/runtime/caching/legacy_cache_api.py 14 0 100%
streamlit/runtime/caching/storage/__init__.py 2 0 100%
streamlit/runtime/caching/storage/cache_storage_protocol.py 31 2 94%
streamlit/runtime/caching/storage/dummy_cache_storage.py 21 0 100%
streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py 67 1 99%
streamlit/runtime/caching/storage/local_disk_cache_storage.py 86 4 95%
streamlit/runtime/connection_factory.py 85 9 89%
streamlit/runtime/context.py 140 0 100%
streamlit/runtime/context_util.py 18 0 100%
streamlit/runtime/credentials.py 139 4 97%
streamlit/runtime/download_data_util.py 27 0 100%
streamlit/runtime/forward_msg_cache.py 23 2 91%
streamlit/runtime/forward_msg_queue.py 63 4 94%
streamlit/runtime/fragment.py 112 2 98%
streamlit/runtime/media_file_manager.py 110 7 94%
streamlit/runtime/media_file_storage.py 15 0 100%
streamlit/runtime/memory_media_file_storage.py 73 0 100%
streamlit/runtime/memory_session_storage.py 15 0 100%
streamlit/runtime/memory_uploaded_file_manager.py 46 1 98%
streamlit/runtime/metrics_util.py 193 12 94%
streamlit/runtime/pages_manager.py 59 2 97%
streamlit/runtime/runtime.py 251 18 93%
streamlit/runtime/runtime_util.py 30 1 97%
streamlit/runtime/script_data.py 16 0 100%
streamlit/runtime/scriptrunner/__init__.py 5 0 100%
streamlit/runtime/scriptrunner/exec_code.py 49 5 90%
streamlit/runtime/scriptrunner/magic.py 83 1 99%
streamlit/runtime/scriptrunner/magic_funcs.py 10 1 90%
streamlit/runtime/scriptrunner/script_cache.py 27 0 100%
streamlit/runtime/scriptrunner/script_runner.py 230 27 88%
streamlit/runtime/scriptrunner_utils/__init__.py 0 0 100%
streamlit/runtime/scriptrunner_utils/exceptions.py 11 1 91%
streamlit/runtime/scriptrunner_utils/script_requests.py 106 5 95%
streamlit/runtime/scriptrunner_utils/script_run_context.py 134 2 99%
streamlit/runtime/secrets.py 242 26 89%
streamlit/runtime/session_manager.py 60 1 98%
streamlit/runtime/state/__init__.py 7 0 100%
streamlit/runtime/state/common.py 52 2 96%
streamlit/runtime/state/presentation.py 19 4 79%
streamlit/runtime/state/query_params.py 134 5 96%
streamlit/runtime/state/query_params_proxy.py 71 0 100%
streamlit/runtime/state/safe_session_state.py 77 9 88%
streamlit/runtime/state/session_state.py 440 33 92%
streamlit/runtime/state/session_state_proxy.py 62 8 87%
streamlit/runtime/state/widgets.py 15 1 93%
streamlit/runtime/stats.py 138 21 85%
streamlit/runtime/theme_util.py 46 1 98%
streamlit/runtime/uploaded_file_manager.py 39 3 92%
streamlit/runtime/websocket_session_manager.py 97 0 100%
streamlit/source_util.py 36 1 97%
streamlit/string_util.py 92 8 91%
streamlit/temporary_directory.py 18 1 94%
streamlit/testing/__init__.py 0 0 100%
streamlit/testing/v1/__init__.py 2 0 100%
streamlit/testing/v1/app_test.py 242 6 98%
streamlit/testing/v1/element_tree.py 1371 87 94%
streamlit/testing/v1/local_script_runner.py 71 2 97%
streamlit/testing/v1/util.py 17 0 100%
streamlit/time_util.py 28 1 96%
streamlit/type_util.py 138 12 91%
streamlit/url_util.py 39 5 87%
streamlit/user_info.py 87 8 91%
streamlit/util.py 38 1 97%
streamlit/version.py 3 0 100%
streamlit/watcher/__init__.py 3 0 100%
streamlit/watcher/event_based_path_watcher.py 181 24 87%
streamlit/watcher/folder_black_list.py 14 1 93%
streamlit/watcher/local_sources_watcher.py 127 9 93%
streamlit/watcher/path_watcher.py 42 3 93%
streamlit/watcher/polling_path_watcher.py 55 2 96%
streamlit/watcher/util.py 49 1 98%
streamlit/web/__init__.py 0 0 100%
streamlit/web/bootstrap.py 153 20 87%
streamlit/web/cache_storage_manager_config.py 5 0 100%
streamlit/web/cli.py 186 17 91%
streamlit/web/server/__init__.py 5 0 100%
streamlit/web/server/app_static_file_handler.py 29 3 90%
streamlit/web/server/authlib_tornado_integration.py 42 5 88%
streamlit/web/server/bidi_component_request_handler.py 65 8 88%
streamlit/web/server/browser_websocket_handler.py 115 31 73%
streamlit/web/server/component_file_utils.py 24 0 100%
streamlit/web/server/component_request_handler.py 55 4 93%
streamlit/web/server/media_file_handler.py 65 9 86%
streamlit/web/server/oauth_authlib_routes.py 118 18 85%
streamlit/web/server/oidc_mixin.py 46 0 100%
streamlit/web/server/routes.py 90 7 92%
streamlit/web/server/server.py 188 11 94%
streamlit/web/server/server_util.py 67 5 93%
streamlit/web/server/stats_request_handler.py 59 5 92%
streamlit/web/server/upload_file_request_handler.py 59 14 76%
streamlit/web/server/websocket_headers.py 19 1 95%
TOTAL 20960 1511 93%

📊 View detailed coverage comparison

@github-actions
Copy link
Contributor

Summary

This PR improves keyboard accessibility for Markdown/Heading anchor links and related tooltip behavior by making anchor icons keyboard focusable/visible on focus, stabilizing heading accessible names via aria-labelledby, adding focus styles for markdown links, and introducing a Playwright helper (tab_until_focused) to reduce e2e flakiness.

Code Quality

  • Good patterns: The aria-label on the anchor icon and aria-hidden on the SVG are solid accessibility improvements (frontend/lib/src/components/shared/StreamlitMarkdown/StreamlitMarkdown.tsx L254-L266). The aria-labelledby approach to prevent action icons from polluting the heading’s accessible name is well explained and scoped to only cases where action elements exist (StreamlitMarkdown.tsx L317-L355).
  • Potential a11y regression: The Escape handling for focus-triggered tooltips blurs the active element (frontend/lib/src/components/shared/Tooltip/Tooltip.tsx L141-L164). This closes the tooltip, but it also removes focus from the trigger, which can break keyboard flow (next Tab often restarts from the top of the document). See recommendation Implement Caching object to support running code blocks only once #1.
  • Link focus styling fallback: In markdown styles, a:focus removes the outline, while the visible ring is only applied to :focus-visible (frontend/lib/src/components/shared/StreamlitMarkdown/styled-components.ts L42-L52). If :focus-visible isn’t supported (or behaves inconsistently), focused links may become effectively invisible. See recommendation Improve caching code #2.

Test Coverage

  • Frontend unit tests:
    • Added coverage for aria-labelledby behavior when help is present and when the anchor icon is present (frontend/lib/src/components/shared/StreamlitMarkdown/StreamlitMarkdown.test.tsx L426-L464).
    • Added Escape-dismiss behavior test for focus-triggered tooltips (frontend/lib/src/components/shared/Tooltip/Tooltip.test.tsx L98-L116). The test currently encodes the “blur on Escape” semantics, which is exactly the behavior I’m concerned about.
  • E2E tests:
    • Added keyboard navigation coverage for heading anchor icon visibility and activation (e2e_playwright/st_heading_test.py L160-L182).
    • Added similar coverage for markdown heading anchors (e2e_playwright/st_markdown_test.py L321-L347).
    • The new tab_until_focused helper is aligned with the e2e best-practice guidance to avoid brittle “N tabs” assumptions (e2e_playwright/shared/app_utils.py L1007-L1056).

Overall: tests cover the new behaviors well, but I’d like the tooltip Escape semantics adjusted (and tests updated accordingly).

Backwards Compatibility

  • No public Python API or protobuf changes.
  • Frontend changes are additive (ARIA attributes, focus styles). The main behavioral change is tooltip dismissal semantics and anchor icon visibility mechanics.

Security & Risk

Recommendations

  1. Fix Escape-to-dismiss tooltips without blurring the trigger.

    • Where: frontend/lib/src/components/shared/Tooltip/Tooltip.tsx L141-L164.
    • Why: Blurring removes focus from the trigger, which is typically not expected for tooltips/popovers and can disrupt keyboard navigation.
    • Suggestion: If BaseWeb supports it, prefer an explicit onEsc/onEscape handler on StatefulTooltip (similar to Popover usage in frontend/lib/src/components/widgets/DataFrame/Tooltip.tsx L82-L84). If not, consider moving StatefulTooltip into a controlled-open pattern (track isOpen and pass it into the component) so Escape can close the tooltip while keeping focus on the trigger.
    • Follow-up: Update frontend/lib/src/components/shared/Tooltip/Tooltip.test.tsx L98-L116 to assert the tooltip closes but the trigger retains focus.
  2. Avoid removing focus outline without a fallback.

    • Where: frontend/lib/src/components/shared/StreamlitMarkdown/styled-components.ts L42-L52.
    • Why: outline: none on :focus can make focus invisible in environments where :focus-visible isn’t applied.
    • Suggestion: Either remove the &:focus { outline: none } rule, or provide a visible focus style for :focus as a fallback (and then optionally refine for :focus-visible).
  3. (Optional) Make tab_until_focused even more Playwright-native.

    • Where: e2e_playwright/shared/app_utils.py L1007-L1056.
    • Suggestion: Consider using expect(locator).to_be_focused() within a bounded retry/wait helper instead of evaluate(':focus') (keeps behavior closer to Playwright’s auto-waiting). This is optional—current implementation is reasonable.

Verdict

CHANGES REQUESTED: Core accessibility intent is strong, but the current Escape handling for focus-triggered tooltips removes focus from the trigger, which is likely a keyboard UX regression.


This is an automated AI review. Please verify the feedback and use your judgment.

@github-actions github-actions bot added the do-not-merge PR is blocked from merging label Dec 16, 2025
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 8f4981c to 970be49 Compare December 16, 2025 23:56
Copy link
Contributor

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

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

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 970be49 to b9ebcd3 Compare December 17, 2025 00:07
Copy link
Contributor

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

Copilot reviewed 7 out of 13 changed files in this pull request and generated no new comments.

@sfc-gh-bnisco sfc-gh-bnisco marked this pull request as ready for review December 17, 2025 00:56
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown branch from 5678480 to 11d03f4 Compare December 17, 2025 16:48
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch 2 times, most recently from a97d86d to 13c6d1e Compare December 17, 2025 16:52
@sfc-gh-bnisco sfc-gh-bnisco changed the base branch from 12-12-_feat_improve_accessibility_of_tooltips_and_markdown to graphite-base/13378 December 17, 2025 17:20
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 13c6d1e to 2b8e1d2 Compare December 17, 2025 17:20
@graphite-app graphite-app bot changed the base branch from graphite-base/13378 to develop December 17, 2025 17:21
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 2b8e1d2 to 8a2c991 Compare December 17, 2025 17:21
Copy link
Collaborator

@mayagbarnes mayagbarnes left a comment

Choose a reason for hiding this comment

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

This is great!
Non-blocking, but perhaps we should sync with Jessi on design for the focus styling as accessibility asks will likely increase. Posting before/after just for our future reference.

Before:
Screenshot 2025-12-17 at 10 11 56 a m
Screenshot 2025-12-17 at 10 11 50 a m
After:
Screenshot 2025-12-17 at 10 06 08 a m
Screenshot 2025-12-17 at 10 06 03 a m

@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from 8a2c991 to c1661f5 Compare December 18, 2025 17:25
@sfc-gh-bnisco sfc-gh-bnisco force-pushed the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch from c1661f5 to 2e5419f Compare December 18, 2025 17:28
Copy link
Collaborator Author

sfc-gh-bnisco commented Dec 22, 2025

Merge activity

  • Dec 22, 5:24 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Dec 22, 5:24 PM UTC: @sfc-gh-bnisco merged this pull request with Graphite.

@sfc-gh-bnisco sfc-gh-bnisco merged commit 8f70c31 into develop Dec 22, 2025
44 checks passed
@sfc-gh-bnisco sfc-gh-bnisco deleted the 12-12-_feat_improve_accessibility_of_tooltips_and_markdown_split branch December 22, 2025 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:bugfix PR contains bug fix implementation impact:users PR changes affect end users security-assessment-completed Security assessment has been completed for PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make title/header anchors keyboard accessible

3 participants