OpenCart is a free, open-source PHP shopping cart that powers a large share of small and mid-size independent stores, and its accessibility profile is shaped by two things: a default theme that has barely changed in years, and a marketplace of third-party themes and extensions of wildly inconsistent quality. Out of the box the default theme is built on an older Bootstrap front end, so it gives you a responsive grid and semantic buttons for free, but it also carries a set of recurring failures that show up on almost every default install. Product option selectors - the radio buttons, checkboxes, and select menus that drive a product's variants - are frequently rendered without their labels programmatically associated, so a screen reader user hears 'radio button' with no idea whether it controls size or colour. The image thumbnail gallery on the product page is a set of linked images that often lack meaningful alt text and open a lightbox that does not trap or return focus. Quantity-discount tables and specification tables are sometimes built as layout tables without header associations. The 'Add to Cart' confirmation is a visually-styled alert injected with JavaScript that is never announced to assistive technology, so a screen reader user cannot tell whether the action succeeded. Form-heavy pages - registration, checkout, the contact form - rely on the theme's field markup, which mixes properly-labelled inputs with placeholder-only ones depending on the version. On top of all that, the moment a store owner installs a third-party theme or a 'quick view' or 'ajax filter' extension, the accessibility baseline resets, because marketplace authors are not held to any accessibility standard. OpenCart ships no built-in accessibility checker, so every fix below is verified with axe, WAVE, or Lighthouse plus a manual keyboard and screen reader pass on the published storefront. This checklist follows the path a shopper takes from category page to confirmed order.

Common Accessibility Issues

critical

Product Option Controls Without Programmatic Labels

WCAG 1.3.1

OpenCart renders product options (size, colour, material) as radio buttons, checkboxes, or select menus, but the option name is often a styled <label> or <span> that is not programmatically tied to the inputs. A screen reader user hears 'radio button, not checked' with no indication of what the option is or which group it belongs to, so choosing the right variant becomes guesswork.

How to fix:

Associate every option group with its controls. Wrap each option group in a <fieldset> with a <legend> carrying the option name, and give each radio/checkbox a <label> whose for attribute matches the input id. For select menus, connect a visible <label> to the <select>. Confirm with a screen reader that focusing an option announces both the group name and the choice.

Before
<div class="form-group required">
  <span>Size</span>
  <input type="radio" name="option[226]" value="5"> Small
  <input type="radio" name="option[226]" value="6"> Large
</div>
After
<fieldset class="form-group required">
  <legend>Size</legend>
  <input type="radio" id="opt-5" name="option[226]" value="5">
  <label for="opt-5">Small</label>
  <input type="radio" id="opt-6" name="option[226]" value="6">
  <label for="opt-6">Large</label>
</fieldset>
critical

Add-to-Cart Confirmation Never Announced to Screen Readers

WCAG 4.1.3

When a shopper adds a product, OpenCart shows a green success alert injected with JavaScript and slides the cart total up. None of this is exposed to assistive technology, so a screen reader user gets no confirmation the item was added and may add it repeatedly or assume the button is broken.

How to fix:

Render the confirmation message into an ARIA live region so it is announced automatically. Add a container with aria-live="polite" (or role="status") that is present in the DOM on page load, and write the success or error text into it after the add-to-cart request returns. Keep the message text specific ('Added 1 x T-shirt to your cart').

Before
<!-- injected on success, invisible to AT -->
<div class="alert alert-success">Success: You have added ... to your cart!</div>
After
<!-- present on load, announced on update -->
<div id="cart-status" role="status" aria-live="polite"></div>
<script>
  document.getElementById('cart-status').textContent =
    'Added 1 x T-shirt to your cart';
</script>
serious

Product Thumbnail Gallery and Lightbox Trap or Lose Focus

WCAG 2.1.2

The product image gallery is a set of linked thumbnails that open a magnifier/lightbox overlay. In the default theme and many extensions the overlay does not move focus to itself, does not trap focus while open, cannot be closed with the Escape key, and does not return focus to the triggering thumbnail on close - leaving keyboard users stranded behind the image.

How to fix:

Make the lightbox a proper modal: on open, move focus into it; constrain Tab order to the overlay while it is open; support Escape and a visible, labelled close button; and return focus to the thumbnail that opened it on close. If your theme's lightbox library cannot do this, replace it with an accessible one or link thumbnails directly to the full image.

Before
<a class="thumbnail" href="large.jpg" onclick="openLightbox()">
  <img src="thumb.jpg" alt="">
</a>
<!-- overlay opens, focus stays on page behind it -->
After
<a class="thumbnail" href="large.jpg">
  <img src="thumb.jpg" alt="Blue running shoe, side view">
</a>
<div role="dialog" aria-modal="true" aria-label="Product image">
  <button aria-label="Close image">x</button>
  <img src="large.jpg" alt="Blue running shoe, side view">
</div>
serious

Missing or Generic Alt Text on Product and Thumbnail Images

WCAG 1.1.1

OpenCart auto-fills the image alt attribute with the product name only if you set it; bulk imports and many themes leave thumbnails with empty or duplicated alt text. Because each product page shows a main image plus several thumbnails of the same item, screen reader users hear the same product name repeated or nothing at all, with no way to tell the views apart.

How to fix:

Give the main product image alt text describing what the product is, and give each thumbnail alt text describing its specific view ('front', 'sole detail', 'worn on model'). Set the image SEO/alt fields in the product editor, and for theme-generated thumbnails ensure the template outputs a meaningful alt rather than echoing the product title on every image.

Before
<img src="main.jpg" alt="">
<img src="t1.jpg" alt="Running Shoe">
<img src="t2.jpg" alt="Running Shoe">
After
<img src="main.jpg" alt="Blue running shoe, side view">
<img src="t1.jpg" alt="Running shoe, sole tread close-up">
<img src="t2.jpg" alt="Running shoe worn on a runner">
serious

Low-Contrast Buttons, Prices, and Sale Badges in the Default Theme

WCAG 1.4.3

The default OpenCart palette uses light grey secondary text, muted link colours, and sale/special prices in a red that frequently fails the 4.5:1 contrast ratio against white. Store owners then pick brand button colours for visual punch without checking contrast, so primary 'Add to Cart' and 'Checkout' buttons can be unreadable for low-vision shoppers.

How to fix:

Check every interactive and informational colour pair against WCAG: body and secondary text and button text need at least 4.5:1 (3:1 for large text 24px/18.66px bold). Adjust the theme's CSS variables for button background, special-price red, and muted text until they pass. Do not rely on colour alone to mark a sale price - keep the 'Special'/'Sale' word too.

Before
.price-new { color: #ff6b6b; } /* ~2.5:1 on white */
.btn-primary { background:#9ec1ff; color:#fff; } /* fails */
After
.price-new { color: #c0392b; } /* >=4.5:1 on white */
.btn-primary { background:#1659b8; color:#fff; } /* >=4.5:1 */
moderate

Specification and Quantity-Discount Tables Without Header Associations

WCAG 1.3.1

Product specification tables and quantity-discount tables are often built as plain grids of <td> cells with the top row visually bold but not marked as headers. Screen reader users navigating the table cell by cell hear values with no column or row context ('512', '7 days', '5%') and cannot tell what each number means.

How to fix:

Use real table semantics: mark column and row headers with <th> and an appropriate scope attribute, and give the table a <caption> describing its purpose. For the quantity-discount block, make the quantity and price columns explicit headers so each discount row is understandable on its own.

Before
<table>
  <tr><td><b>Quantity</b></td><td><b>Price</b></td></tr>
  <tr><td>5+</td><td>$18.00</td></tr>
</table>
After
<table>
  <caption>Quantity discounts</caption>
  <tr><th scope="col">Quantity</th><th scope="col">Price</th></tr>
  <tr><td>5+</td><td>$18.00</td></tr>
</table>
serious

Checkout and Registration Fields Relying on Placeholders

WCAG 3.3.2

Depending on the OpenCart version and theme, some checkout and registration inputs use placeholder text ('First Name', 'E-Mail') as the only prompt. The placeholder vanishes on input, so screen reader users may hear nothing on focus and shoppers who pause lose track of what a field expects - a frequent cause of abandoned checkouts for older users.

How to fix:

Give every checkout, registration, and address field a persistent visible <label> tied to the input by for/id, and keep required-field and error messaging text (not colour or an asterisk alone). Add autocomplete attributes (given-name, family-name, email, tel, postal-code) so assistive tech and browsers can fill fields accurately.

Before
<input type="text" name="firstname" placeholder="First Name">
After
<label for="input-firstname">First Name</label>
<input type="text" id="input-firstname" name="firstname"
       autocomplete="given-name" required>
serious

Third-Party Extensions and Themes Reset the Accessibility Baseline

WCAG 4.1.2

OpenCart's marketplace has no accessibility review, so quick-view popups, ajax category filters, mega-menus, and one-page-checkout extensions routinely add custom widgets built from non-semantic <div> and <span> elements with no roles, names, or keyboard support. A store that was usable on the default theme can become unusable after a single extension install.

How to fix:

Treat every extension as a regression risk: before and after installing, run axe/WAVE and a keyboard-only pass on the pages it touches. Prefer extensions whose authors document accessibility or use native HTML controls. For custom widgets, ensure each has a correct role, an accessible name, keyboard operability, and a visible focus indicator - or do not ship it.

Before
<div class="quickview-btn" onclick="openQuickView(42)">
  Quick View
</div>
After
<button type="button" class="quickview-btn"
        onclick="openQuickView(42)">
  Quick View<span class="sr-only"> of Blue Running Shoe</span>
</button>

OpenCart-Specific Tips

  • Start from a theme whose author documents accessibility rather than the oldest free template; many OpenCart paid themes still ship the legacy markup that fails on labels and focus management, so verify before you build.
  • Set the image alt/SEO field on every product (and on the manufacturer logos and banner modules) in the admin, and audit bulk-imported products separately - CSV imports almost never populate meaningful alt text.
  • Override the success/error notification template to write into an aria-live region instead of an invisible injected alert, so add-to-cart, wishlist, and compare actions are announced. This single change fixes a status-message failure across the whole store.
  • Run the checkout end to end with the keyboard only and a screen reader before launch: OpenCart's default checkout, the guest path, and any one-page-checkout extension each render fields differently, so test the exact path your customers use.
  • Re-run axe or WAVE after every extension or theme update. OpenCart's plugin model means the storefront markup can change without notice, and an update that adds an ajax filter or mega-menu can silently introduce keyboard traps.

axe DevTools (browser extension)

A free browser extension that scans any rendered OpenCart page for WCAG issues such as missing labels, low contrast, and ARIA errors. Run it on category, product, cart, and checkout pages after installing any theme or extension.

WAVE Web Accessibility Evaluation Tool

A free WebAIM tool (web and extension) that flags missing form labels, empty links, heading-structure problems, and contrast failures visually on the page - useful for spotting OpenCart's placeholder-only fields and unlabeled option controls.

NVDA screen reader

A free, open-source Windows screen reader. Use it to confirm product options announce their group and label, add-to-cart confirmations are spoken, and the image lightbox manages focus correctly - the failures automated tools cannot fully detect.

Where OpenCart Accessibility Issues Concentrate

Plugin / Tool AreaDefault Theme RiskWhat To Check
Product options variant selectors Size/colour controlsHigh - labels often not associated with inputsFieldset + legend per group, label per control, announced by screen reader
Add to cart status message Success/error alertHigh - injected alert not announcedaria-live / role=status region present on load and updated on action
Image gallery thumbnails + lightbox Magnifier overlayHigh - no focus trap, no Escape, no focus returnModal pattern: move focus in, trap, Escape closes, return focus
Checkout forms Registration and checkout fieldsMedium - placeholder-only fields in some versionsVisible labels, autocomplete attributes, text error messages
Extensions marketplace add-ons Quick view, ajax filters, mega-menuHigh - no accessibility review on the marketplaceKeyboard + screen reader test every page the extension touches

Frequently Asked Questions

Is OpenCart accessible out of the box?

Partially. The default theme is built on Bootstrap, so it gives you a responsive grid, real

Do OpenCart extensions affect accessibility?

Heavily. The OpenCart marketplace applies no accessibility review, so quick-view popups, ajax filters, mega-menus, and one-page-checkout extensions frequently add custom widgets built from non-semantic markup with no roles, keyboard support, or focus management. An extension can turn a usable store into an inaccessible one in one click, so test every page an extension touches with a keyboard and a screen reader before and after installing it.

Does OpenCart need to comply with the European Accessibility Act?

If you sell to consumers in the EU, almost certainly. The European Accessibility Act (EAA), in force since 28 June 2025, treats consumer e-commerce as a covered service, and it points to EN 301 549, which in turn requires WCAG 2.1 Level AA for web content. That means your OpenCart product pages, cart, and checkout need to meet WCAG 2.1 AA. This is general information, not legal advice - confirm your specific obligations with a qualified professional.

How do I make OpenCart product options accessible?

Associate each option group with its controls. Wrap the radio/checkbox group in a

with a carrying the option name (Size, Colour), and give each input a