Search code examples
svgdocusaurus

Docusaurus strips some attributes from inline SVGs; need ID for accessibility


I'm using inline SVGs like this:

Content of icon-checkmark.svg:

<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 46 46"><title id="myTitleID">An accessible title</title><path {…} /></svg>

Import & inline:

import CheckmarkSvg from '/img/site-components/icon-checkmark.svg';

<CheckmarkSvg role="image" aria-labelledby="myTitleID" className="myClass" />

But Docusaurus strips the title's ID attribute from the rendered SVG.

Is there a workaround for this? Without it, the title is not accessible in some browsers.


Solution

  • As @ccprog stated in their comment, Docusaurus depends on SVGR, which depends on SVGO. SVGO was the library ultimately doing this. However, recent versions of Docusaurus no longer remove the <title> anymore, as Docusaurus preconfigured SVGR/SVGO to omit that behavior.

    Reference: fix(utils): make SVGO not remove title

    Regarding the removal of <title> in general, indeed this is a flaw with SVGO, and this behavior will be disabled in the next major release.


    While this is no longer an ongoing issue, I'll drop an answer for how to address issues like this, in case someone wants to reconfigure other SVGO plugins through Docusaurus.

    I recommend resolving this through Docusaurus' Lifecycle APIs. One can use the configureWebpack function to alter the SVGO options.

    To do this, create a custom plugin for Docusaurus in your repository.

    src/plugins/configure-svgo.js

    /**
     * Docusaurus uses SVGR internally, which in turn uses SVGO. This alters the
     * SVGO config and merges the changes back into Docusaurus' webpack config.
     *
     * @returns {Object}
     */
    function configureSvgo() {
      return {
        name: 'configure-svgo',
        configureWebpack(config) {
          /** @type {object[]} */
          const rules = config.module.rules;
    
          const rule = rules.find((rule) => {
            /** @type {string|undefined} */
            const loader = rule.oneOf?.[0]?.use?.[0]?.loader;
            return loader && loader.includes("/@svgr/");
          });
    
          const svgoConfig = rule.oneOf[0].use[0].options.svgoConfig;
          // alter svgoConfig with whatever changes you need
    
          return {
            mergeStrategy: {
              "module.rules": "replace"
            },
            module: { rules }
          };
        }
      };
    }
    
    module.exports = configureSvgo;
    

    You can alter svgoConfig by appending plugins to the plugins array, or disabling plugins in the default preset, etc. In this case, you'd want to disable a plugin.

    Once you've created the plugin, you'd then need to enable it in your Docusaurus config:

    docusaurus.config.js

    // …
      plugins: [
        // …
        "./src/plugins/configure-svgo.js"
      ],
    // …
    

    Docusaurus will now pass your SVGO config to SVGR/SVGO, so SVG's will still be optimized, but will also fulfil your project requirements.