đĒ Google ZX & Axe CLI
Setup
The script iterates each route, spawns axe-core via ZX, and prints accessibility violations to the terminal.
To use google/zx and @axe-core/cli you'll need to install them.
1npm i -g zx @axe-core/cli
Next, I've added a script run command inside my package.json pointing to a .mjs script file.
1"scripts": {2 "start": "parcel serve ./src/index.html --no-cache",3 ...4 "axe": "zx ./src/scripts/axe/index.mjs",5 },
The Script
The script itself is pretty small thanks to google/zx providing lightweight wrappers around child_process.
1#!/usr/bin/env zx23/*4README56GitHub: https://github.com/google/zx78Install (global): npm i zx -g first && @axe-core/cli -g910Node.js will treat .cjs files as CommonJS modules and .mjs files as ECMAScript modules.11It will treat .js files as whatever the default module system for the project is12(which is CommonJS unless package.json says "type": "module",).13*/1415const answer = await question(16 `What URL would you like to run axe against?17 [1]: localhost18 [2]: thejoecodes1920 `21);2223const baseUrl =24 answer === '1' ? 'http://localhost:1234' : 'https://www.thejoecodes.com';2526const pageRoutes = [27 '/articles',28 '/updates',29 '/about',30 '/arcade',31 '/articles/the-halloween-event-loop',32 '/articles/start-using-sass-mixins',33 '/articles/javascript-promises',34 '/articles/vanilla-javascript',35 '/articles/javascript-string-methods-cheat-sheet',36 '/articles/exploring-typescript-basic-types',37 '/articles/css-custom-properties-theme',38 '/articles/productive-tooling',39 '/articles/web-accessibility',40 '/articles/rem-is-not-for-layouts',41 '/articles/responsive-mixin',42 '/articles/git-ssh-config',43 '/articles/accessibility-linting',44];4546const urls = pageRoutes.map((pageRoute) => `${baseUrl}${pageRoute}`);4748await urls.forEach((url) => $`npx axe ${url}`);
- The $`command` uses the spawn function from the child_process package to execute a string.
- The question() function is a wrapper around readline. You can see the additional boilerplate needed without Google ZX when using readline over in my productive tooling article.
Final Thoughts
It's fair to say I'll be re-writing my node scripts with zx by Google. It just removes so much extra boilerplate and makes writing scripts clean, fun and easy.
Was this useful?
Thanks for reading! Time for one more?
const next = themeColors[index].trim()body.setAttribute('dark-theme-color', next)
đ¨ Theme Picker
27 Oct 2021 âĸ đ 15 min read âĸ Updated 15 Mar 2026Creating a scalable theme picker with CSS custom properties.
<Emoji emoji="â" label="high five" />// <span role="img" aria-label="high five">â</span><img src={src} /> // missing alt prop
â Accessible Emojis
06 Oct 2021 âĸ đ 5 min read âĸ Updated 15 Mar 2026Using eslint-plugin-jsx-a11y to catch accessibility issues during development.