<?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: Praise Agbabiaka</title>
    <description>The latest articles on DEV Community by Praise Agbabiaka (@praiztech).</description>
    <link>https://dev.to/praiztech</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1177654%2F3dda3c81-77fc-4fc1-8a05-93d4488c0e1e.jpg</url>
      <title>DEV Community: Praise Agbabiaka</title>
      <link>https://dev.to/praiztech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/praiztech"/>
    <language>en</language>
    <item>
      <title>A design system fixes accessibility once, if it's the only source</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Sun, 30 Aug 2026 22:26:01 +0000</pubDate>
      <link>https://dev.to/praiztech/a-design-system-fixes-accessibility-once-if-its-the-only-source-1i07</link>
      <guid>https://dev.to/praiztech/a-design-system-fixes-accessibility-once-if-its-the-only-source-1i07</guid>
      <description>&lt;p&gt;Do accessibility remediation long enough and you arrive at the same conclusion every time. Stop fixing instances. Fix the thing that generates them.&lt;/p&gt;

&lt;p&gt;The natural end of that logic is the design system. Fix the button component once, and every button in the product inherits the fix. One change, every instance. It's the most leveraged accessibility work you can do.&lt;/p&gt;

&lt;p&gt;It also rests on an assumption that can quietly fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Fixed at the source" assumes there is one source
&lt;/h2&gt;

&lt;p&gt;When you fix the component, you fix every instance that goes through the component. That's the promise, and it's real.&lt;/p&gt;

&lt;p&gt;But somewhere in the codebase there may be two or three buttons that don't go through it. A div with a click handler someone wrote in a hurry. A one-off in a corner of the app the component never reached. A copy made before the component existed and was never migrated.&lt;/p&gt;

&lt;p&gt;The canonical component gets corrected. The hand-rolled copies don't, because they were never using the source.&lt;/p&gt;

&lt;p&gt;So your fix at the source covers the instances that use it and misses the ones that bypass it. The re-audit passes on the pages built from the component and fails on the pages that reinvented it. Same fix, same product, different result, and nothing in the component diff tells you why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The closing step isn't diffing the component
&lt;/h2&gt;

&lt;p&gt;It's grepping the pattern.&lt;/p&gt;

&lt;p&gt;The real end of a source-level fix isn't confirming the component is right. It's searching the codebase for every place the pattern was reimplemented, and deciding, for each one, whether to fold it back into the component or fix it where it sits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A source-level fix isn't done when the source is right. It's done when nothing bypasses it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  This is the real argument for design systems, and the real work of one
&lt;/h2&gt;

&lt;p&gt;A design system is the honest answer to "fix the system, not the instance." It's the one place an accessible pattern can live so that using it is the default.&lt;/p&gt;

&lt;p&gt;But a design system isn't a folder of accessible components. It's a commitment that the accessible pattern is the canonical path, and the easiest one.&lt;/p&gt;

&lt;p&gt;Those two conditions carry all the weight. If the accessible menu is harder to adopt than hand-rolling a dropdown, people hand-roll the dropdown, and you are back to instances, now scattered across a codebase that looks like it has a design system. The component exists. It just isn't the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  So it's two disciplines, not one
&lt;/h2&gt;

&lt;p&gt;Building the pattern accessibly is the part everyone pictures. It's also the smaller part.&lt;/p&gt;

&lt;p&gt;Making it the single source is the work. That means making it the path of least resistance, so bypassing it is harder than adopting it. It means catching the reinventions in code review, before they become the copies nobody knows about. And it means, every so often, grepping for the pattern and folding the strays back in.&lt;/p&gt;

&lt;p&gt;An accessible component fixes every instance that uses it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The work is making sure every instance uses it.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>designsystems</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Accessibility remediation is software engineering, not a checklist</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Sun, 23 Aug 2026 22:18:46 +0000</pubDate>
      <link>https://dev.to/praiztech/accessibility-remediation-is-software-engineering-not-a-checklist-3d64</link>
      <guid>https://dev.to/praiztech/accessibility-remediation-is-software-engineering-not-a-checklist-3d64</guid>
      <description>&lt;p&gt;An accessibility audit is invaluable. It identifies problems that might otherwise go unnoticed, provides a structured view of a product's accessibility, and gives a team a concrete starting point for remediation.&lt;/p&gt;

&lt;p&gt;But an audit report is a starting point, not a remediation plan.&lt;/p&gt;

&lt;p&gt;It's tempting to treat the findings as the job: work through the list, close each issue, ship. But a finding tells you what went wrong in the rendered experience. It doesn't necessarily tell you why it happened, where it should be fixed, or how to prevent it from happening again.&lt;/p&gt;

&lt;p&gt;That's where accessibility remediation becomes software engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  A finding is a symptom, not a location
&lt;/h2&gt;

&lt;p&gt;An audit tells you what is wrong with the output. It doesn't tell you where in the system to fix it.&lt;/p&gt;

&lt;p&gt;If the same failure shows up on ten pages, fixing ten pages may address the reported instances without addressing the cause. The more useful question is where the failure is produced.&lt;/p&gt;

&lt;p&gt;A shared component. A template. A design-system primitive. The content. A third-party script.&lt;/p&gt;

&lt;p&gt;The right fix often changes structure, not just an attribute.&lt;/p&gt;

&lt;p&gt;The problem isn't working through findings one by one. That's often necessary. The problem is treating each finding as an isolated task without asking what produced it and whether the fix will hold up.&lt;/p&gt;

&lt;p&gt;Fix only the output, and the failure can return the next time that output is generated. Fix the thing that generates it, and the fix has a much better chance of surviving the next change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remediation carries technical debt too
&lt;/h2&gt;

&lt;p&gt;There is always a faster path. A line of JavaScript that rewrites the DOM after render. A one-off ARIA patch. A duplicated component variant that's "accessible this time."&lt;/p&gt;

&lt;p&gt;Each can close a finding. Each can also leave the codebase worse: a script maintaining server-rendered markup indefinitely, conflicting ARIA, or a fix that breaks when the markup underneath it changes.&lt;/p&gt;

&lt;p&gt;None of these approaches are always wrong. Sometimes they are the right solution given the constraints of the system.&lt;/p&gt;

&lt;p&gt;But they should be deliberate engineering decisions.&lt;/p&gt;

&lt;p&gt;A remediation should leave the code in a better state, not simply move the problem somewhere harder to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regression is part of the problem
&lt;/h2&gt;

&lt;p&gt;A fix applied only to the output is vulnerable to regression when that output is regenerated. Reuse a component in a new context. Copy a template. Take an upstream update. Onboard a developer who copies the existing pattern without knowing it's broken.&lt;/p&gt;

&lt;p&gt;A fix built into the system is more resilient. When correctness is built into the component, template, design system, or development process, it doesn't have to be re-decided every time the same pattern is used.&lt;/p&gt;

&lt;p&gt;That's the difference between fixing an instance and fixing the system that produced it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A fix that doesn't survive the next change was never really a fix.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  This is engineering, not a separate track
&lt;/h2&gt;

&lt;p&gt;I don't treat accessibility remediation as separate from software engineering.&lt;/p&gt;

&lt;p&gt;The requirement comes from the Web Content Accessibility Guidelines (WCAG). The failure surfaces in an audit. Deciding how to fix it is an engineering problem.&lt;/p&gt;

&lt;p&gt;It means understanding the architecture, the rendering model, the component boundaries, the dependencies, the upgrade path, the tests, and the people who maintain the code after you leave.&lt;/p&gt;

&lt;p&gt;There isn't always a universally correct code change. There is a correct engineering approach for the system in front of you.&lt;/p&gt;

&lt;p&gt;The same finding needs a different fix in a React design system than in a Liquid theme, and knowing which is the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good remediation leaves the system better
&lt;/h2&gt;

&lt;p&gt;The measure of good remediation isn't simply whether the reported issues are gone. It's whether the software is better equipped to remain accessible after the work is finished.&lt;/p&gt;

&lt;p&gt;Can the next developer understand and maintain the fix? Does the component or design system make the accessible pattern the default path? Is the implementation resilient to platform and dependency updates? Can new features build on the same accessible foundation instead of recreating the problem?&lt;/p&gt;

&lt;p&gt;This is what makes accessibility remediation software engineering.&lt;/p&gt;

&lt;p&gt;You're not just changing markup until it passes a test. You're making decisions about architecture, abstractions, maintainability, dependencies, and how the software will evolve.&lt;/p&gt;

&lt;p&gt;The audit identifies the problem. The remediation is the engineering work of solving it well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closing a finding is the easy part. Fixing the system that produced it is the work.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>remediation</category>
    </item>
    <item>
      <title>AI Can Find the Failure. Who Decides What the Fix Should Be?</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Sun, 16 Aug 2026 23:14:58 +0000</pubDate>
      <link>https://dev.to/praiztech/ai-can-find-the-failure-who-decides-what-the-fix-should-be-18o5</link>
      <guid>https://dev.to/praiztech/ai-can-find-the-failure-who-decides-what-the-fix-should-be-18o5</guid>
      <description>&lt;p&gt;AI is changing accessibility remediation fast. It can find common accessibility failures, explain them, and increasingly write the fix. That's real, and it's useful.&lt;/p&gt;

&lt;p&gt;But finding a failure is not the same as deciding what the fix should be.&lt;/p&gt;

&lt;p&gt;The gap is easy to miss because it doesn't always produce an obviously wrong answer. Sometimes it produces a confident, plausible fix that is wrong for reasons that only become apparent when you understand the interaction in context.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example
&lt;/h2&gt;

&lt;p&gt;I recently worked through an accessible predictive search for a Shopify storefront with an AI assistant. A combobox with a listbox, screen-reader support, the usual.&lt;/p&gt;

&lt;p&gt;In places, it was genuinely good. It identified the right interaction pattern and the roles and interaction model it depends on. It reviewed the theme's existing JavaScript and caught real bugs, ones I'd have taken longer to find by hand.&lt;/p&gt;

&lt;p&gt;Keyboard navigation that didn't exist.&lt;/p&gt;

&lt;p&gt;An Escape handler that wiped the user's typed query.&lt;/p&gt;

&lt;p&gt;A live region toggled with &lt;code&gt;aria-hidden&lt;/code&gt; instead of being left in the page, so it announced inconsistently across screen readers.&lt;/p&gt;

&lt;p&gt;That's detection working well.&lt;/p&gt;

&lt;p&gt;Then it started proposing fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plausible, and wrong
&lt;/h2&gt;

&lt;p&gt;It moved the search suggestions into a separate region, reached with the Tab key.&lt;/p&gt;

&lt;p&gt;Reasonable-looking. Also wrong.&lt;/p&gt;

&lt;p&gt;In a combobox, Tab moves focus out of the widget. A user navigating the suggestions with arrow keys shouldn't have to Tab into a separate region to reach them. The model had identified the right pattern and then proposed an interaction that contradicted it.&lt;/p&gt;

&lt;p&gt;I had to catch that.&lt;/p&gt;

&lt;p&gt;Another fix involved two different types of actions in the same listbox. Some options navigated to a product page and displayed the product image and name. Others rewrote the query and contained only the suggested query.&lt;/p&gt;

&lt;p&gt;Visually, the distinction was obvious. A sighted user could immediately tell a product result from a suggested query.&lt;/p&gt;

&lt;p&gt;But the interaction model wasn't.&lt;/p&gt;

&lt;p&gt;A listbox presents its children as options within a uniform selection model. When those options perform fundamentally different actions, the interaction model no longer matches what the options actually do.&lt;/p&gt;

&lt;p&gt;The better solution was to rethink the interaction rather than try to make the existing one more accessible.&lt;/p&gt;

&lt;p&gt;Again, the proposed fix was technically plausible. It just didn't survive contact with the actual interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that's easy to miss
&lt;/h2&gt;

&lt;p&gt;Here's what made this risky.&lt;/p&gt;

&lt;p&gt;The wrong fixes arrived with exactly the same fluency and confidence as the right ones. Nothing in the response flagged "this one is probably wrong."&lt;/p&gt;

&lt;p&gt;If I hadn't understood how focus moves through a combobox, or thought carefully about what information actually reaches a screen-reader user through the accessibility tree, I could have shipped both.&lt;/p&gt;

&lt;p&gt;That's the real gap.&lt;/p&gt;

&lt;p&gt;The model had understood the visual UI, the ARIA pattern, and the relevant standards, but it hadn't reliably reasoned through what the resulting interaction communicated to the person using it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection is not judgment. Fluency is not judgment.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the corrections came from
&lt;/h2&gt;

&lt;p&gt;The important part wasn't simply knowing the WCAG success criteria or looking up the relevant ARIA pattern.&lt;/p&gt;

&lt;p&gt;It was understanding how the interaction actually works for people using assistive technology.&lt;/p&gt;

&lt;p&gt;That understanding comes from accessibility expertise, testing, standards, technical experience, and importantly, lived experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how do we use AI?
&lt;/h2&gt;

&lt;p&gt;Not by pretending it's useless.&lt;/p&gt;

&lt;p&gt;It flagged real bugs, explained the standards, and drafted code faster than I would have. I'll keep using it for that.&lt;/p&gt;

&lt;p&gt;But AI should remain inside the remediation loop, not become the end of it.&lt;/p&gt;

&lt;p&gt;AI can detect. AI can explain. AI can propose.&lt;/p&gt;

&lt;p&gt;Engineers still need to evaluate the proposed solution in the context of the actual application. And disabled users still need to tell us whether the resulting experience actually works.&lt;/p&gt;

&lt;p&gt;The goal isn't to keep AI out of accessibility.&lt;/p&gt;

&lt;p&gt;It's to use it where it is strong without handing it the parts of the process that require judgment, context, and human experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI can often tell you what's broken. It can even suggest how to fix it. But it can't be the final authority on whether we've actually made the experience better for the people we're building it for.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>ai</category>
      <category>webdev</category>
      <category>shopify</category>
    </item>
    <item>
      <title>A broken heading hierarchy is an architecture problem, not a markup one</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Sun, 09 Aug 2026 21:59:34 +0000</pubDate>
      <link>https://dev.to/praiztech/a-broken-heading-hierarchy-is-an-architecture-problem-not-a-markup-one-489n</link>
      <guid>https://dev.to/praiztech/a-broken-heading-hierarchy-is-an-architecture-problem-not-a-markup-one-489n</guid>
      <description>&lt;p&gt;On a recent BigCommerce remediation, an audit flagged the heading hierarchy. Levels skipped and jumped across the page, so the structure a screen-reader user navigates by didn't hold together.&lt;/p&gt;

&lt;p&gt;The checklist fix is obvious. Open each template, retag the headings, close the finding.&lt;/p&gt;

&lt;p&gt;But the levels weren't the bug. They were the symptom.&lt;/p&gt;

&lt;p&gt;Each heading was hardcoded into its own template. A section rendered an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; because whoever wrote that template picked &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, with no view of where it would sit on the assembled page. Nothing owned the hierarchy. It emerged, wrongly, from dozens of local decisions.&lt;/p&gt;

&lt;p&gt;That's the real problem, and it's architectural.&lt;/p&gt;

&lt;p&gt;A reusable heading component has no inherent level. The same block might be an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; on one page and an &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; nested inside a region on another. Its correct level depends on where it sits, not on what it is.&lt;/p&gt;

&lt;p&gt;Any component that bakes in a fixed level is going to be wrong somewhere because it can't see its own context.&lt;/p&gt;

&lt;p&gt;So the fix isn't to hardcode a different level. It's to stop hardcoding heading levels altogether and render each heading from one place that receives its level from whatever owns the page structure.&lt;/p&gt;

&lt;p&gt;The principle is portable. The idiom changes per stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BigCommerce (Handlebars): a single partial that receives the level as a parameter, replacing heading markup repeated across a dozen templates.&lt;/li&gt;
&lt;li&gt;Shopify (Liquid): a snippet that takes the level through &lt;code&gt;render&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;React: pass the level as a prop, or use context when the hierarchy needs to be derived from component composition.&lt;/li&gt;
&lt;li&gt;Astro: let the parent own the structure and pass the level through props, rather than having the child commit to a level it can't know from its own context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different mechanisms, one move.&lt;/p&gt;

&lt;p&gt;Headings render in a single place, and the level is an input from context, not a constant.&lt;/p&gt;

&lt;p&gt;It's also the fix that lasts. A hardcoded level regresses the moment a section is reused or a template is copied. A contextual one stays correct because the decision lives with the page structure instead of being re-decided everywhere.&lt;/p&gt;

&lt;p&gt;That's the difference between closing a finding and fixing the system that produced it.&lt;/p&gt;

&lt;p&gt;The accessibility failure was in the markup. The fix was in the architecture.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>bigcommerce</category>
      <category>react</category>
    </item>
    <item>
      <title>You don't have to choose between Shopify updates and accessibility fixes</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Mon, 03 Aug 2026 01:23:41 +0000</pubDate>
      <link>https://dev.to/praiztech/you-dont-have-to-choose-between-shopify-updates-and-accessibility-fixes-fm8</link>
      <guid>https://dev.to/praiztech/you-dont-have-to-choose-between-shopify-updates-and-accessibility-fixes-fm8</guid>
      <description>&lt;p&gt;A while back, a developer told me something that stuck with me. He said fixing Shopify Liquid files is a hassle, because customizations don't scale with theme updates. The moment you start editing a theme, you've effectively forked it, and every future update has to be diffed and re-applied by hand.&lt;/p&gt;

&lt;p&gt;He's not wrong. That's effectively how maintaining a customized Shopify theme works.&lt;/p&gt;

&lt;p&gt;It's also why many teams avoid deep changes to a live theme, accessibility remediation included.&lt;/p&gt;

&lt;p&gt;Accessibility fixes often require changes that only exist in Liquid templates: adding semantic HTML, correcting heading hierarchy, exposing labels to assistive technology, or fixing landmark structure. Those aren't changes you can reliably layer on afterward with CSS or JavaScript.&lt;/p&gt;

&lt;p&gt;But "that's just how Shopify works" is where the conversation usually stops. I don't think it should stop there. The fork isn't a Shopify problem. It's a process problem. And process problems have process answers.&lt;/p&gt;

&lt;p&gt;Solving the update problem comes down to two ideas: isolate changes so most of them never collide with an update, and keep a clean, greppable record of the changes that can't be isolated so the manual diff stays small and predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core problem
&lt;/h2&gt;

&lt;p&gt;Two facts about Shopify themes create the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom edits don't carry through theme updates.&lt;/strong&gt; When Shopify ships a new version of the base theme, it doesn't merge your changes in. You get the new version, and reconciling your customizations is on you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A GitHub-connected theme stops receiving Shopify's theme updates.&lt;/strong&gt; Once a theme is connected to GitHub, Shopify's built-in "Update available" workflow no longer applies to that theme. If you want upstream theme updates, you need to bring them into your Git workflow yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you want two things at once: version control and the ability to take upstream updates. Do you have to choose one? No. You keep them in separate places on purpose. That's the core idea, and everything below is just the mechanics of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup, before any remediation starts
&lt;/h2&gt;

&lt;p&gt;This groundwork is what makes the update painless later. Do it first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolate CSS and JavaScript into custom files
&lt;/h3&gt;

&lt;p&gt;Any styling or scripting change goes into its own custom asset files instead of being edited into the theme's existing files. These almost never conflict with an update. Because these are new assets rather than modifications to the theme's files, upstream theme updates rarely touch them, so Git treats them as independent additions rather than conflicting edits. The one exception is the line that loads them: the &lt;code&gt;stylesheet_tag&lt;/code&gt; or &lt;code&gt;script_tag&lt;/code&gt; that enqueues these custom assets lives in Liquid, usually in &lt;code&gt;theme.liquid&lt;/code&gt;, so that single hookup is a Liquid edit an update can collide with. Tag it with your &lt;code&gt;A11Y-REMEDIATION&lt;/code&gt; marker like any other Liquid change. With that one line accounted for, most of your work is gone from the diff before the diff even starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tag every Liquid change and keep a list
&lt;/h3&gt;

&lt;p&gt;Liquid is the part you can't fully isolate. Sometimes you have to edit a section or snippet directly. For every one of those edits, leave a clear comment describing what changed, and maintain a running list of every Liquid file you touched.&lt;/p&gt;

&lt;p&gt;One refinement pays off later. Use a consistent, greppable marker in those comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="c"&gt; A11Y-REMEDIATION: added aria-label + visible focus state to search toggle &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;endcomment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your "list of changed Liquid files" isn't something you maintain by hand and hope is complete. It's one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rl&lt;/span&gt; &lt;span class="s2"&gt;"A11Y-REMEDIATION"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Designate an unconnected copy of the live theme to receive updates
&lt;/h3&gt;

&lt;p&gt;Before you start, duplicate the live theme and leave that copy &lt;em&gt;disconnected&lt;/em&gt; from GitHub. Because it isn't connected, it stays eligible for Shopify's updates. This copy is your update pipeline. The connected repo is your source of truth. Keeping them apart is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The update workflow
&lt;/h2&gt;

&lt;p&gt;When Shopify releases a new version of the base theme, this is how you take it without losing remediation work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: bring the update into version control
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Update the theme copy in the Shopify admin. Shopify generates a new &lt;em&gt;Updated Copy&lt;/em&gt; of the theme with the new version applied.&lt;/li&gt;
&lt;li&gt;Create a backup branch from the connected repo's &lt;code&gt;main&lt;/code&gt;. If anything goes sideways, you have a clean restore point.&lt;/li&gt;
&lt;li&gt;Create an &lt;code&gt;update&lt;/code&gt; branch and pull the code from the &lt;em&gt;Updated Copy&lt;/em&gt; into it, not from the live theme. This gets the upstream changes into Git where you can actually diff them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 2: reconcile, with a focus on every Liquid change
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Merge &lt;code&gt;update&lt;/code&gt; into &lt;code&gt;dev&lt;/code&gt; using &lt;code&gt;--no-commit&lt;/code&gt; (&lt;code&gt;git merge --no-commit --no-ff update&lt;/code&gt;). This leaves the merge staged but uncommitted, giving you a chance to inspect both conflicting and automatically merged changes before creating the merge commit. The &lt;code&gt;--no-ff&lt;/code&gt; flag forces an actual merge commit so you always land in that reviewable staged state, even when Git could have fast-forwarded.&lt;/li&gt;
&lt;li&gt;Diff every Liquid file you modified during remediation, file by file. This is the one deliberately manual step, and it's where your tagged comments and file list earn their keep. You know exactly which files to check, so you're reviewing a short list, not the whole theme. Keep, adapt, or discard each incoming change so accessibility fixes are preserved without missing legitimate improvements in the updated theme.&lt;/li&gt;
&lt;li&gt;Commit to &lt;code&gt;dev&lt;/code&gt; once the diff is clean, then merge &lt;code&gt;dev&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 3: push back to Shopify, in the right order
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Push &lt;code&gt;main&lt;/code&gt; to the Updated Copy, not to Live yet. Order matters here, to avoid schema errors: push the configuration files first, &lt;code&gt;config/settings_schema.json&lt;/code&gt; and &lt;code&gt;config/settings_data.json&lt;/code&gt;, then push the remaining theme files. Pushing the config first means that if there's a schema problem, the sync fails here, before the rest of the theme is touched, so you fix the JSON discrepancy and retry instead of discovering the problem after everything else has synced.&lt;/li&gt;
&lt;li&gt;Verify the Updated Copy on Shopify before publishing. Alongside the usual schema and functional checks, re-run your accessibility checks here: an upstream update can change base-theme files you never touched and quietly regress accessibility along the way, so confirm the copy still holds up before it goes live. Only then publish it as the Live theme.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this holds up
&lt;/h2&gt;

&lt;p&gt;Notice what each piece is doing. The unconnected copy keeps you eligible for updates. Version control keeps your work reviewable and reversible. Isolated CSS and JavaScript mean most of your changes never enter the diff at all. Tagged Liquid comments turn the unavoidable manual step into a bounded, predictable one. The config-first push order fails loudly and early instead of quietly and late.&lt;/p&gt;

&lt;p&gt;None of this makes Shopify merge your changes. That was never on the table. What it does is shrink the manual work to the smallest surface possible and make every risky step recoverable.&lt;/p&gt;

&lt;p&gt;The theme stays maintainable. Updates stay boring. "We customized it" stops meaning "we're stuck on this version forever."&lt;/p&gt;

&lt;p&gt;That developer's complaint was fair. It just wasn't the end of the story. Shopify sets the constraint. A disciplined workflow keeps it manageable.&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>a11y</category>
      <category>webdev</category>
      <category>liquid</category>
    </item>
    <item>
      <title>Building a Component Library: From First Component to Fully Automated Pipeline</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Tue, 19 May 2026 21:20:19 +0000</pubDate>
      <link>https://dev.to/praiztech/building-a-component-library-from-first-component-to-fully-automated-pipeline-4dg4</link>
      <guid>https://dev.to/praiztech/building-a-component-library-from-first-component-to-fully-automated-pipeline-4dg4</guid>
      <description>&lt;p&gt;I was asked to architect and build a React component library from the ground up.&lt;/p&gt;

&lt;p&gt;The problem was clear. We kept rebuilding the same components across different applications. The same buttons, inputs, modals, and layouts, recreated from scratch every time. Someone needed to own a component library and that someone ended up being me.&lt;/p&gt;

&lt;p&gt;I nodded like I had a plan. I didn't.&lt;/p&gt;

&lt;p&gt;I'd never built a component library before. I didn't know how to structure one, how to distribute one, or honestly how to scope one. But I figured the best way to learn was to start.&lt;/p&gt;

&lt;p&gt;So I started small. Buttons. Inputs. The boring stuff that touches everything.&lt;/p&gt;

&lt;p&gt;I focused on getting the foundations right, and I made the decision very early on that accessibility would be baked in from day one. Every component designed to be usable by keyboard users, screen readers, and other assistive technologies from the start. Not as a future improvement. Not as a "nice to have." Just part of the standard.&lt;/p&gt;

&lt;p&gt;Then, the library kept growing.&lt;/p&gt;

&lt;p&gt;Today, it's documented and hosted in Storybook, published as an npm package, and fully automated with CI/CD pipelines that handle Storybook deployments and npm publishing on every release.&lt;/p&gt;

&lt;p&gt;What started as a vague ask turned into real infrastructure the team relies on daily.&lt;/p&gt;

&lt;p&gt;A few things I'd tell anyone starting from zero:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't need to know everything upfront. Start with the smallest components and let the architecture reveal itself.&lt;/li&gt;
&lt;li&gt;Treat accessibility like functionality. If it doesn't work with a keyboard, it's not done.&lt;/li&gt;
&lt;li&gt;Automate early. Setting up CI/CD for publishing and deployment saved me more time than I expected.&lt;/li&gt;
&lt;li&gt;Document everything. Storybook isn't just a demo tool. It's how the team actually adopts the library.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap between "I have no idea what to do" and "this is running in production" is smaller than you think. It's just a lot of small steps.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>a11y</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Building My First Wagtail Site</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Mon, 30 Oct 2023 04:09:01 +0000</pubDate>
      <link>https://dev.to/praiztech/building-my-first-wagtail-site-3hj7</link>
      <guid>https://dev.to/praiztech/building-my-first-wagtail-site-3hj7</guid>
      <description>&lt;p&gt;Software development is an ever-changing field. Often, one has to pick up new technologies rather quickly. This was the case for me with Wagtail. And thanks to its simplicity, I was able to do so in no time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Wagtail?
&lt;/h2&gt;

&lt;p&gt;An opportunity to improve the accessibility of websites built with Wagtail opened up recently. And I immediately jumped on it. I was so excited at the prospect of putting my accessibility skills to use that I didn’t give much thought to the fact that I had no experience with Wagtail. I figured I could pick up Wagtail quickly enough if I put my mind to it. And since I learn best by doing, I decided to build a blog site to gain hands-on experience with Wagtail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Wagtail?
&lt;/h2&gt;

&lt;p&gt;Wagtail is an open-source Content Management System built on Django. So, much of the process for building websites with Django translates directly to Wagtail. But Wagtail abstracts the need to define &lt;code&gt;urls&lt;/code&gt;, &lt;code&gt;views&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt; functionality. In Wagtail, emphasis is placed on page and page content. Every page is built from a Django model that inherits from Wagtail’s &lt;code&gt;Page&lt;/code&gt; model. Wagtail also provides a number of custom template tags and filters that extend the capabilities of the Django templating engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Blog Site
&lt;/h2&gt;

&lt;p&gt;I decided that my blog site would have a home page, a blog index page, blog post pages, and an about page. Since a home app comes out of the box with Wagtail, I only had to create a base and blog app for my Wagtail project.&lt;/p&gt;

&lt;p&gt;In the home app, I updated the &lt;code&gt;HomePage&lt;/code&gt; model to include fields for a hero image, heading, introduction and link to the blog index page. I defined the image and link fields as a &lt;code&gt;Foreignkey&lt;/code&gt; to Wagtail’s &lt;code&gt;Image&lt;/code&gt; and &lt;code&gt;Page&lt;/code&gt; models, respectively.&lt;/p&gt;

&lt;p&gt;As the name suggests, the base app defined functionalities shared across apps within the project. It contained &lt;code&gt;snippets&lt;/code&gt; for the site logo, main menu and breadcrumb navigation. Within this app, I constructed a &lt;code&gt;ContentBlock&lt;/code&gt; that allowed me to dynamically add subheading, image, list and rich text content to a page. This &lt;code&gt;ContentBlock&lt;/code&gt; inherited from &lt;code&gt;StreamBlock&lt;/code&gt;. It was used to define a &lt;code&gt;StreamField&lt;/code&gt; to populate the body field of the about and blog post pages. Because the about page didn’t belong in the home or blog app, I defined a &lt;code&gt;StandardPage&lt;/code&gt; model to create it.&lt;/p&gt;

&lt;p&gt;The blog app held models and templates for the blog index page and blog post pages. I defined the &lt;code&gt;BlogPage&lt;/code&gt; model as child page of the &lt;code&gt;BlogIndexPage&lt;/code&gt;. And I populated the blog index page with meta data for each blog post. Thus, a new blog site was built.&lt;/p&gt;

&lt;p&gt;I’m glad that I can now add Wagtail to my toolkit as a web developer. If you’d like to see my code, check out the &lt;a href="https://github.com/praiztech/praiztech_blog" rel="noopener noreferrer"&gt;praiztech_blog repository on GitHub&lt;/a&gt;. I'm still working on the front-end, though.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>webdev</category>
      <category>python</category>
      <category>django</category>
    </item>
    <item>
      <title>Growing My Skill in Web Accessibility</title>
      <dc:creator>Praise Agbabiaka</dc:creator>
      <pubDate>Fri, 27 Oct 2023 12:21:44 +0000</pubDate>
      <link>https://dev.to/praiztech/growing-my-skill-in-web-accessibility-2bij</link>
      <guid>https://dev.to/praiztech/growing-my-skill-in-web-accessibility-2bij</guid>
      <description>&lt;p&gt;As a self-taught web developer, my first impulse whenever I encounter a new concept is to search the Web. There's almost always a blog post or video that explains it in enough detail to help me understand. For the most part, this has been no different for web accessibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Online Resources
&lt;/h2&gt;

&lt;p&gt;Once I learnt about &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility" rel="noopener noreferrer"&gt;web accessibility on Mozilla&lt;/a&gt;, it was quite easy to find other related posts. I found several excellent posts to expand my knowledge of accessible web development. I learnt to write accessible code with semantic Hypertext Markup Language (HTML) elements. I also learnt to test my websites with automated testing tools such as WAVE, axe DevTools and ARC Toolkit. To understand how blind users experience my websites, I learnt to test with NVDA and TalkBack screen readers. I also learnt to enhance the output of screen readers with Accessible Rich Internet Applications (ARIA) when there are no HTML alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning from a Great Mentor
&lt;/h2&gt;

&lt;p&gt;As my knowledge of web accessibility grew, I realized that I was lacking an important skill. I didn't know how to perform a manual accessibility audit. I searched the Web but I couldn't find a simple guide on the process of manual accessibility testing. Yet, I knew I had to gain this skill. Manual auditing is the only way to identify all accessibility issues on a website.&lt;/p&gt;

&lt;p&gt;So, when Rachele DiTullio posted on LinkedIn that they had created &lt;a href="https://racheleditullio.com/projects/accessibility-testing/" rel="noopener noreferrer"&gt;manual accessibility audit videos&lt;/a&gt;, I was excited. First, I watched the videos to understand their testing process. Then, I sent them an email requesting their mentorship. They were very receptive and agreed to mentor me. They agreed to provide weekly testing exercises and give feedback on the results. Thus began my journey into manual web accessibility auditing.&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%2Fwzthbqwtwsfibuj8v6gp.PNG" 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%2Fwzthbqwtwsfibuj8v6gp.PNG" alt="A worksheet in a manual accessibility testing workbook showing the scope of the test" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;&lt;strong&gt;My first manual accessibility testing workbook&lt;/strong&gt;
  &lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Journey So Far
&lt;/h2&gt;

&lt;p&gt;As I've performed manual accessibility audits, my skill have evolved over time. I've learnt to break down each webpage into smaller sections to test. I'm learning to better interpret the Web Content Accessibility Guidelines (WCAG). I'm learning how WCAG failures impact the web experience of users with disabilities. It's a journey. I'm getting better at it. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webaccessibility</category>
      <category>accessiblecode</category>
      <category>a11y</category>
    </item>
  </channel>
</rss>
