Making Element Web More Accessible and Observable: Fixing a High-Contrast Regression and Improving Sentry Debugging
This is a submission for *DEV's Summer Bug Smash: Clear the Lineup** powered by Sentry.*
Project Overview
For the Summer Bug Smash, I contributed to Element Web, the open-source Matrix collaboration client for the web.
Element is a large TypeScript-based monorepo that provides the web experience for Matrix, an open and decentralised communication protocol. It supports features such as real-time messaging, rooms, direct conversations, search, media, calls, integrations, moderation, accessibility features, and more.
What made this project particularly interesting to me was its scale and architecture. Element Web is not simply a standalone web application. It shares functionality with the wider Matrix ecosystem and is also used as the foundation for Element Desktop, where the same web application runs inside an Electron environment.
That means seemingly small frontend issues can have a much larger impact:
- An incorrect colour can make an interface unusable for users relying on high-contrast themes.
- A regression can easily return if there is no automated test protecting the behaviour.
- A desktop-specific runtime environment can produce stack traces that are difficult to map back to the original source code.
- Good observability is essential when debugging software that runs across multiple environments.
During the challenge, I worked on two areas of the project:
- Accessibility: fixing an illegible Spotlight interaction in the High Contrast theme.
- Observability: improving Sentry's ability to resolve and group errors originating from Element Desktop.
Both contributions were merged into Element Web.
Bug Fix or Performance Improvement
1. Fixing an Accessibility Regression in High Contrast Mode
The first issue affected the Spotlight dialogue when Element was using the High Contrast theme.
When a Spotlight result was hovered or keyboard-selected, the text could be rendered in a light colour against a light background. The result was technically present, but effectively unreadable.
This defeated the purpose of a high-contrast accessibility mode.
The root cause was in the high-contrast theme styling. Several Spotlight states were using $background as the text colour while the corresponding hover background was also a light colour.
In other words:
Light text
+
Light background
=
Poor contrast / unreadable UI
The problem affected multiple Spotlight surfaces, including:
- Public room search results
- Recently viewed results
- Keyboard shortcut hints
- Active filter chips
- Related dropdown states
I fixed this by changing the affected states to use $primary-content, providing an appropriate dark foreground against the light high-contrast background.
The fix was submitted in:
PR #34465 — Fix illegible text on hovered Spotlight results in high-contrast theme
The PR was merged into Element Web's develop branch.
But I didn't want the fix to simply make the UI look correct on my machine.
I wanted to make sure the regression could not silently come back.
So I added automated accessibility coverage that validates the actual WCAG contrast ratio.
The tests verify that the affected elements achieve a contrast ratio of at least 4.5:1, which is the WCAG AA requirement for normal text.
More importantly, I verified that the tests fail when the fix is reverted.
The fixed implementation passes with the required contrast ratio, while the original implementation produced a ratio of approximately 1.38:1.
That gave the change a much stronger guarantee than simply checking whether two colour values were different.
Code
Accessibility Fix
PR: #34465 — Fix illegible text on hovered Spotlight results in high-contrast theme
The PR was merged by the Element Web maintainers after review.
The implementation included:
- High Contrast theme corrections
- Spotlight accessibility regression tests
- WCAG contrast validation
- Playwright-based end-to-end coverage
- Follow-up improvements to use Axe-based accessibility checks
- CI validation and maintainer review
Sentry Improvement
PR: #34667 — Add Sentry frame rewriting for Element Desktop integration
This PR was also merged into develop.
My Improvements
From "Fixing the Bug" to "Preventing the Bug"
One of my main goals during this contribution was not to stop at the smallest possible code change.
A production-quality fix should answer two questions:
Why did this happen?
and
How do we make sure it doesn't happen again?
For the accessibility issue, I therefore approached the problem in layers.
Step 1 — Reproduce the problem
I first reproduced the issue in the High Contrast theme and narrowed it down to the Spotlight interaction states.
This helped separate the actual bug from unrelated theme styling.
Step 2 — Identify the root cause
Instead of simply changing a colour until the UI looked better, I traced the theme variables involved in the foreground and background styling.
The problematic combination was effectively:
foreground: $background
background: $quinary-content
Both values were too light when used together in this context.
The appropriate solution was to use the theme's dark content colour:
foreground: $primary-content
This preserved the existing design system instead of introducing a new hard-coded colour.
Step 3 — Validate accessibility mathematically
This was an important part of my approach.
Accessibility shouldn't depend solely on visual inspection.
I added tests that calculate/check the actual contrast ratio and enforce:
Contrast ratio >= 4.5:1
This means the test is validating the accessibility requirement itself, rather than merely validating an implementation detail.
Step 4 — Protect against regression
I tested the behaviour against multiple Spotlight states instead of protecting only the original failing element.
This makes the test suite more representative of the actual user experience.
I also verified the regression behaviour by reverting the fix locally.
The test failed against the original implementation and passed after the fix.
That gave me confidence that the test was actually capable of catching the bug rather than simply passing because the assertion was too weak.
Step 5 — Work with the project's existing quality gates
The contribution also went through Element's existing contribution workflow, including CI checks and maintainer review.
The PR received review from Element contributors and was ultimately merged into develop.
That process was valuable because working on a mature open-source project is very different from fixing a bug in a personal repository.
The goal isn't just:
"My code works."
It is:
"My change fits the project's architecture, conventions, accessibility requirements, tests, and maintenance expectations."
Best Use of Sentry
This is the part of the submission I am particularly excited about.
Instead of adding Sentry artificially just to qualify for the challenge, I worked on an existing observability problem in Element Desktop.
The Problem
Element Desktop uses Element Web as its application UI, but it doesn't run it from a conventional https:// origin.
The application is served from:
vector://vector/webapp
When an exception occurred inside the desktop renderer, Sentry could therefore receive stack frames containing paths such as:
vector://vector/webapp/bundles/<hash>/bundle.js
This creates a problem for source-map resolution.
The source code may exist in Sentry, but if the frame path doesn't match the expected artifact path, Sentry cannot correctly map the minified stack frame back to the original source.
The practical result is exactly what you don't want from an error-monitoring system:
Production crash
↓
Sentry receives error
↓
Stack frame has custom vector:// path
↓
Source map cannot resolve it correctly
↓
Developer sees an unsymbolicated stack trace
↓
Debugging becomes harder
It could also prevent errors from being grouped as expected with equivalent errors from the web environment.
This was the problem addressed in:
PR #34667 — Add Sentry frame rewriting for Element Desktop integration
Understanding the Root Cause
While investigating the Sentry setup, I found that Element explicitly disables Sentry's default integrations and builds its own integration list.
Because of that configuration, the rewriteFramesIntegration integration wasn't enabled.
That meant Sentry received the frame filenames exactly as the runtime produced them.
For the desktop application, that included the custom:
vector://vector/webapp
origin.
The key insight was that this wasn't fundamentally a "Sentry isn't working" problem.
Sentry was receiving the error correctly.
The problem was the identity of the stack frame path.
The same application code was being represented using a runtime-specific origin that the source-map resolver wasn't expecting.
The Solution
I added Sentry's frame rewriting integration:
Sentry.rewriteFramesIntegration({
root: "vector://vector/webapp",
prefix: "app://",
});
The purpose is straightforward:
vector://vector/webapp/bundles/<hash>/bundle.js
↓
rewrite
↓
app://bundles/<hash>/bundle.js
This normalises the custom Electron/desktop origin into the conventional app:// form used for source-map resolution.
An important detail is that the change is intentionally scoped.
For the normal web application, frames don't start with:
vector://vector/webapp
so the rewriting has no effect.
That means the same Sentry configuration can support both environments without introducing unnecessary behaviour for the browser application.
I Didn't Just Assume It Worked
One of the most valuable parts of this work was validating the behaviour against Sentry itself.
I sent an identical fabricated crash through the relevant configurations and compared how the stack frame was represented.
The objective was not simply to confirm that the application compiled.
I wanted to verify the complete observability path:
Application
↓
Exception
↓
Sentry SDK
↓
Frame rewriting
↓
Sentry event
↓
Source-map resolution
↓
Readable stack trace
This is what I believe makes the Sentry contribution meaningful for this challenge.
Sentry wasn't used as a decorative dependency.
It was used to solve a real production debugging problem.
The resulting improvement means that when a desktop error occurs, developers have a much better chance of getting a useful, symbolicated stack trace instead of spending time trying to manually interpret an opaque production stack.
Why This Matters
Error monitoring is only valuable if the information it provides can actually be used to debug the problem.
An error like:
Error
at bundle.js:482193:17
is dramatically less useful than:
Error
at SomeComponent.tsx:142:17
Source maps bridge that gap.
But source maps are only useful when the stack-frame paths can be matched to the uploaded artifacts.
The frame rewriting change makes that relationship work correctly for Element Desktop's custom runtime origin.
In other words, I didn't just improve error collection.
I improved the debuggability of production errors.
Additional Engineering Work
I also added unit-test coverage around the Sentry configuration to make the behaviour easier to maintain.
This is important because Sentry's configuration in Element is intentionally customised rather than using every default integration.
Without a regression test, a future refactor could accidentally remove or alter the frame rewriting integration and reintroduce the original problem.
The contribution therefore protects both:
- The runtime behaviour.
- The configuration that makes the runtime behaviour possible.
What I Learned
This challenge reinforced something I believe is important in software engineering:
The hardest bugs are often not caused by complex algorithms.
Sometimes the underlying problem is a mismatch between two systems.
In the accessibility issue, the mismatch was between:
Theme foreground
×
Theme background
×
Accessibility requirements
In the Sentry issue, the mismatch was between:
Runtime origin
×
Stack-frame paths
×
Source-map artifacts
In both cases, solving the problem required understanding the system around the code rather than changing a single line blindly.
I also learned a lot from working within a mature open-source project:
- How to navigate a large TypeScript monorepo.
- How to trace a UI issue back to theme variables.
- How to write regression tests that validate user-visible behaviour.
- How to reason about WCAG contrast requirements.
- How browser and Electron environments differ.
- How source maps interact with runtime stack frames.
- How Sentry integrations affect production observability.
- How to validate an observability change against the actual monitoring pipeline.
- How to respond to maintainer feedback and iterate on a PR.
- How to make a change that fits an existing engineering system rather than building around it.
Final Result
During the Summer Bug Smash, I contributed two merged improvements to Element Web:
Accessibility
Fixed: Unreadable Spotlight text in High Contrast mode.
Improved: WCAG contrast validation and automated regression coverage.
Result: Spotlight interactions remain readable and protected against future regressions.
Observability
Fixed: Sentry stack-frame resolution for Element Desktop's custom vector:// origin.
Improved: Frame rewriting and Sentry-specific unit-test coverage.
Result: Desktop errors can be represented using source-map-compatible frame paths, making production crashes easier to symbolicate, group, and debug.
Closing Thoughts
Open source gives developers an opportunity to work on software that is already being used by real people.
For me, this challenge wasn't about adding the largest feature or making the most lines of code.
It was about making two small but meaningful improvements to a production system:
Make the interface more accessible.
Make production failures easier to understand.
And most importantly, make both improvements durable through automated testing.
I'm grateful to the Element maintainers and contributors for reviewing, challenging, and ultimately merging these changes.
A bug fix is useful.
A bug fix with a regression test is better.
A bug fix with a regression test, clear reasoning, and production observability is the kind of engineering I want to keep practising.
🏆 Thanks to DEV and Sentry for the Summer Bug Smash challenge — and to the Element community for the opportunity to contribute.
Contributions
- Element Web: https://github.com/element-hq/element-web
- Accessibility Fix — PR #34465: https://github.com/element-hq/element-web/pull/34465
- Sentry Improvement — PR #34667: https://github.com/element-hq/element-web/pull/34667
- DEV Summer Bug Smash: https://dev.to/bugsmash
Top comments (0)