<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Naomi</title>
    <description>The latest articles on DEV Community by Naomi (@naomir).</description>
    <link>https://dev.to/naomir</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3797111%2F0b46abd0-70e6-4dcb-9e33-eaa8d221603a.png</url>
      <title>DEV Community: Naomi</title>
      <link>https://dev.to/naomir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naomir"/>
    <language>en</language>
    <item>
      <title>Accessibility Bugs That Were Actually Architecture Problems</title>
      <dc:creator>Naomi</dc:creator>
      <pubDate>Wed, 27 May 2026 20:01:20 +0000</pubDate>
      <link>https://dev.to/naomir/accessibility-bugs-that-were-actually-architecture-problems-1fmh</link>
      <guid>https://dev.to/naomir/accessibility-bugs-that-were-actually-architecture-problems-1fmh</guid>
      <description>&lt;p&gt;Most accessibility defects don't look serious at first.&lt;/p&gt;

&lt;p&gt;A tester opens a ticket:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"NVDA reads the wrong thing"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Focus disappears after modal close"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Button is not announced"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Keyboard navigation is inconsistent"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first instinct is usually to patch the screen — add an &lt;code&gt;aria-label&lt;/code&gt;, adjust tab order, maybe add a &lt;code&gt;role&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Sometimes that works.&lt;/p&gt;

&lt;p&gt;But after spending years on large enterprise applications built with JSP, Spring MVC, custom tag libraries, jQuery UI dialogs, and reusable framework components, I started noticing a pattern:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many accessibility defects were not really screen-level bugs. They were architecture problems showing up through assistive technology.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The defects that kept repeating
&lt;/h2&gt;

&lt;p&gt;One thing that stood out was how often the same accessibility issues appeared across completely different screens.&lt;/p&gt;

&lt;p&gt;Different business flows. Different developers. Different modules.&lt;/p&gt;

&lt;p&gt;But the same problems.&lt;/p&gt;

&lt;p&gt;That usually meant one thing: the issue existed inside a reusable component or framework pattern.&lt;/p&gt;

&lt;p&gt;Some recurring examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modal dialogs losing focus&lt;/li&gt;
&lt;li&gt;Keyboard navigation escaping overlays&lt;/li&gt;
&lt;li&gt;Icon buttons announced incorrectly&lt;/li&gt;
&lt;li&gt;Custom dropdowns breaking arrow-key navigation&lt;/li&gt;
&lt;li&gt;Focus not returning after close&lt;/li&gt;
&lt;li&gt;Repeated screen reader announcements&lt;/li&gt;
&lt;li&gt;Visually correct controls missing semantic meaning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a certain point, we stopped treating these as isolated defects and started treating them as &lt;strong&gt;reusable engineering patterns&lt;/strong&gt;. That changed how we approached remediation entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  When NVDA read "shuffle" instead of the actual action
&lt;/h2&gt;

&lt;p&gt;One accessibility defect looked harmless at first.&lt;/p&gt;

&lt;p&gt;A tester reported that NVDA announced &lt;code&gt;shuffle&lt;/code&gt; instead of &lt;code&gt;Update Record&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The screen looked perfectly fine visually. The implementation looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"action-button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"material-icons"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;shuffle&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  Update Record
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue was that the Material Icon text itself became part of the accessible name calculation. To a browser, the word &lt;code&gt;shuffle&lt;/code&gt; is still text content unless explicitly hidden from assistive technology.&lt;/p&gt;

&lt;p&gt;The corrected implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"action-button"&lt;/span&gt;
  &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Update Record"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"material-icons"&lt;/span&gt;
    &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    shuffle
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Update Record
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, NVDA correctly announced: &lt;em&gt;"Update Record button"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This was one of those defects that reminded us of something important: &lt;strong&gt;visual correctness and accessibility correctness are not the same thing.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  When aria-label was not the real fix
&lt;/h2&gt;

&lt;p&gt;Another issue involved a button that NVDA would not consistently announce.&lt;/p&gt;

&lt;p&gt;The team tried &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;tabindex&lt;/code&gt;, screen-reader-only text. None of them fully solved it.&lt;/p&gt;

&lt;p&gt;The original implementation looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app:springLink&lt;/span&gt; &lt;span class="na"&gt;page=&lt;/span&gt;&lt;span class="s"&gt;"/submitForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
    &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Submit Form"&lt;/span&gt;
    &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Submit Form"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/app:springLink&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real problem was the custom framework wrapper. The abstraction around the button was interfering with native semantics and focus behavior. The control rendered visually and appeared interactive, but assistive technologies interpreted it inconsistently.&lt;/p&gt;

&lt;p&gt;The more stable solution was simplifying back toward native HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/submitForm"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Submit Form
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This became a recurring lesson: &lt;strong&gt;the farther custom components drift from native HTML behavior, the harder accessibility becomes to maintain predictably.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The modal that looked fine — until you used a screen reader
&lt;/h2&gt;

&lt;p&gt;Modals caused some of the most repeated accessibility defects in the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus escaping the dialog&lt;/li&gt;
&lt;li&gt;Focus not returning after close&lt;/li&gt;
&lt;li&gt;Missing dialog labels&lt;/li&gt;
&lt;li&gt;Keyboard users tabbing into the page behind the modal&lt;/li&gt;
&lt;li&gt;Screen readers announcing stale content&lt;/li&gt;
&lt;li&gt;Duplicate announcements from hidden dialog instances&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One particularly confusing issue involved a session timeout modal. NVDA repeatedly announced:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refresh button&lt;br&gt;&lt;br&gt;
Refresh button&lt;br&gt;&lt;br&gt;
Refresh button&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...even though visually there was only one dialog on screen.&lt;/p&gt;

&lt;p&gt;The root cause was not the button itself. The dialog component was being recreated repeatedly without destroying previous instances. Hidden dialog structures remained in the DOM, and NVDA continued detecting them through the virtual buffer.&lt;/p&gt;

&lt;p&gt;The original implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#timeoutDialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dialog initialization ran multiple times during the session timer lifecycle. The fix involved properly destroying existing instances before recreating them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#timeoutDialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hasClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-dialog-content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#timeoutDialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destroy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#timeoutDialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Session Timeout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visually, the issue was invisible. From a screen reader perspective, the experience was chaotic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This was one of the clearest examples of why automated scans alone are not enough.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Accessibility issues that were really UX issues
&lt;/h2&gt;

&lt;p&gt;Some accessibility defects were technically small but had major workflow impact.&lt;/p&gt;

&lt;p&gt;One recurring category was focus management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closing a modal and losing keyboard position&lt;/li&gt;
&lt;li&gt;Tab order not matching business workflow&lt;/li&gt;
&lt;li&gt;Focus landing on hidden elements&lt;/li&gt;
&lt;li&gt;Keyboard users restarting navigation from the top of the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In transactional enterprise applications with long forms and multi-step workflows, these issues matter a lot.&lt;/p&gt;

&lt;p&gt;One session timeout dialog had three actions: Close, Refresh Session, Return to Login. Visually, the buttons were aligned correctly. But keyboard order felt inconsistent because DOM order and intended workflow didn't match.&lt;/p&gt;

&lt;p&gt;We ended up intentionally designing focus order around user behavior instead of visual layout alone. We also standardised focus restoration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;triggerElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#timeoutDialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;triggerElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That small change improved workflow continuity significantly for keyboard users.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automated testing passed — but real interaction still failed
&lt;/h2&gt;

&lt;p&gt;One thing we repeatedly observed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Axe passed ✓&lt;/li&gt;
&lt;li&gt;Lighthouse passed ✓&lt;/li&gt;
&lt;li&gt;Visual QA passed ✓&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...but real screen reader interaction still felt broken.&lt;/p&gt;

&lt;p&gt;Automated tools were excellent for missing labels, colour contrast, duplicate IDs, and missing form associations. But they couldn't fully validate announcement quality, workflow predictability, interaction consistency, keyboard experience, or screen reader context.&lt;/p&gt;

&lt;p&gt;This became especially obvious in dynamic dialogs, custom dropdowns, reusable JSP components, timer-based UI behavior, and AJAX-rendered content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The most difficult accessibility issues appeared where framework abstractions and dynamic rendering replaced native browser behavior.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Accessibility debt becomes framework debt
&lt;/h2&gt;

&lt;p&gt;One important realization from large enterprise systems: accessibility debt accumulates very similarly to technical debt.&lt;/p&gt;

&lt;p&gt;Over time, applications collect custom wrappers, reusable dialogs, proprietary navigation components, utility JavaScript layers, and framework abstractions.&lt;/p&gt;

&lt;p&gt;Eventually accessibility problems stop belonging to individual screens. &lt;strong&gt;They become framework-level problems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At that point, fixing defects one page at a time becomes inefficient. The better long-term solution is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable accessibility standards&lt;/li&gt;
&lt;li&gt;Component-level remediation&lt;/li&gt;
&lt;li&gt;Documented interaction patterns&lt;/li&gt;
&lt;li&gt;Standardised focus behavior&lt;/li&gt;
&lt;li&gt;Semantic HTML guidelines&lt;/li&gt;
&lt;li&gt;Accessibility validation integrated into development workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That shift changed accessibility from a QA activity into an &lt;strong&gt;engineering practice&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;The biggest accessibility lesson I learned from enterprise systems: screen readers are often exposing deeper interaction and architecture problems that already exist in the application.&lt;/p&gt;

&lt;p&gt;Many defects initially looked like missing labels, incorrect roles, or keyboard issues. But underneath, the real problem was usually broken component abstraction, inconsistent focus behavior, dynamic rendering side effects, or custom UI patterns replacing native browser behavior.&lt;/p&gt;

&lt;p&gt;And in many cases, &lt;strong&gt;the best accessibility fix was not adding more ARIA. It was simplifying the component back toward predictable HTML semantics.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I also built &lt;a href="https://dev.to/naomir/ai-assisted-frontend-reviews-using-gemma-4-567c"&gt;PR Sentinel&lt;/a&gt; — an AI-powered frontend PR reviewer that catches accessibility and UI quality issues before they ship, built with Gemma 4.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>react</category>
    </item>
    <item>
      <title>AI-Assisted Frontend Reviews Using Gemma 4</title>
      <dc:creator>Naomi</dc:creator>
      <pubDate>Thu, 21 May 2026 20:29:56 +0000</pubDate>
      <link>https://dev.to/naomir/ai-assisted-frontend-reviews-using-gemma-4-567c</link>
      <guid>https://dev.to/naomir/ai-assisted-frontend-reviews-using-gemma-4-567c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PR Sentinel analyzes React and TypeScript snippets and generates structured engineering feedback focused on maintainability, accessibility, performance, and UI quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;PR Sentinel is an AI-assisted frontend PR reviewer focused on React and TypeScript engineering quality.&lt;/p&gt;

&lt;p&gt;Developers can paste frontend code snippets and receive structured engineering feedback across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React best practices&lt;/li&gt;
&lt;li&gt;Maintainability&lt;/li&gt;
&lt;li&gt;UI/UX quality&lt;/li&gt;
&lt;li&gt;Accessibility (A11y)&lt;/li&gt;
&lt;li&gt;Component architecture&lt;/li&gt;
&lt;li&gt;State management patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project was inspired by real frontend review pain points commonly seen in enterprise applications, especially issues related to stale closures, infinite re-renders, semantic accessibility structure, and reusable component design.&lt;/p&gt;

&lt;p&gt;Instead of producing generic AI summaries, PR Sentinel organizes feedback into categorized engineering review cards that resemble actual senior-level frontend review comments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foeuvzf809n1okas545x9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foeuvzf809n1okas545x9.jpg" alt="PR Sentinel landing screen with diagnostic sandbox presets, React/TSX input editor, and AI review console interface" width="798" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://frontend-pr-review-assistant.onrender.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo uses a limited development API configuration and may occasionally be unavailable during evaluation periods.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/BL2Cib5c-bU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzy0myl4mvj5e2pd8ro0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzy0myl4mvj5e2pd8ro0.jpg" alt="AI-generated frontend review report showing side-by-side code comparison, React best practices analysis, accessibility suggestions, and refactoring rationale" width="576" height="789"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;(&lt;a href="https://github.com/naomirasamalla/Frontend-PR-Review-Assistant" rel="noopener noreferrer"&gt;https://github.com/naomirasamalla/Frontend-PR-Review-Assistant&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The application allows developers to paste frontend snippets and receive categorized AI-generated engineering review feedback in real time.&lt;/p&gt;

&lt;p&gt;Key Features:&lt;/p&gt;

&lt;p&gt;AI-powered React/TypeScript review analysis&lt;br&gt;
Structured frontend engineering feedback&lt;br&gt;
Accessibility-focused review insights&lt;br&gt;
UI/UX and maintainability recommendations&lt;br&gt;
Real-time review rendering&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;PR Sentinel uses Gemma 4 to analyze React and TypeScript frontend code snippets and generate structured PR-style engineering feedback.&lt;/p&gt;

&lt;p&gt;The project focuses on identifying practical frontend issues such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;infinite render loops&lt;/li&gt;
&lt;li&gt;stale closures in async logic&lt;/li&gt;
&lt;li&gt;unsafe DOM access patterns&lt;/li&gt;
&lt;li&gt;maintainability concerns&lt;/li&gt;
&lt;li&gt;accessibility-related frontend risks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma 4 was selected because the project required fast reasoning over frontend engineering patterns while generating concise, developer-focused review output.&lt;/p&gt;

&lt;p&gt;The model is used to evaluate pasted code snippets and return structured recommendations similar to a lightweight frontend pull request review workflow.&lt;/p&gt;

&lt;p&gt;The application includes built-in diagnostic sandbox scenarios that simulate real frontend engineering issues commonly encountered in React applications.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
  </channel>
</rss>
