Importing SVG Files In Typescript React Project

2023-03-26
React
Typescript
SVG
programming
Web development

Howto

To display SVG files on the page (as e.g. icons or images or other elements), there are several ways depending on circumstances and requirements. For this case, I'm mostly concerned with React project written in Typescript - though for JS (and non-React) projects some of the below options apply as well.

Perhaps the simplest way is to just add it to the component "as is" - because it's a valid markup, things like

    export const ComponentWithSvg = () => (
        <div>
            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="120px" height="120px" viewBox="0 0 120 120" enable-background="new 0 0 120 120" xml:space="preserve">
                <path d="M60,19.089C22.382,19.089,0.053,60,0.053,60S22.382,100.91,60,100.91S119.947,60,119.947,60S97.618,19.089,60,19.089z M59.999,84.409C46.54,84.409,35.59,73.459,35.59,60c0-13.459,10.95-24.409,24.409-24.409c13.459,0,24.409,10.95,24.409,24.409 C84.408,73.459,73.458,84.409,59.999,84.409z"/>
                <circle cx="60" cy="60.583" r="14.409"/>
            </svg>
        </div>
    );

would do just fine. Not reusable, not structured, not viewable independently - but it'd work.

If the project was created with Create React App or uses Parcel v2 or was appropriately configured to process assets automatically, another option is to import it like e.g.

    import iconPath from './iconFile.svg';

    export const ComponentWithSvg = () => (
        <>
            <img src={iconPath}/>
        </>
    );

or in case that imports file data as string, it should be possible to use it as a variable inside the component as e.g.

    import icon from './iconFile.svg';

    export const ComponentWithSvg = () => (
        <>
            {icon}
        </>
    );

There's also an option to turn the icon into a ReactComponent and use it as such - though a bit more work, I think it's the most structurally sound way:

  1. Add type declaration for the .svg files by creating ./src/@types/assets/index.d.ts file with content:

     declare module "\*.svg" {
         import React = require("react");
         const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
         export default ReactComponent;
     }    
    
  2. In tsconfig.json, configure typeRoots parameter to include the types:

     {
         ...
         "typeRoots": ["./src/@types", "./node_modules/@types"],
         ...
     }
    
  3. Import and use it as a component:

     import React from "react";
     import { ReactComponent as SVGIcon } from "./icon.svg";
    
     export const ComponentWithSvg = () => (
         <>
             <SVGIcon />
         </>
     );