javascripthtmlreactjsmaterial-uiascii-art

How to use ascii art within React projects


I am using react and cannot get ascii images to maintain their form in the browser,

<Grid container id="terminal_banner">
            <Grid item xs={10}>
                <pre>
        __ _.--..--._ _
     .-' _/   _/\_   \_'-.
    |__ /   _/\__/\_   \__|
       |___/\_\__/  \___|
              \__/
              \__/       / ``_
               \__/    0/      `-`_
                \__/   |            `'-_                                            
             ____\__/__|_               `'-_
       . - '             ' -.               `-_    
      /                      \                 `-_     
~~~~~~~  ~~~~~ ~~~~~  ~~~ ~~~  ~~~~~~~~~~~~  ~~~~~ #{`_///)__/)_.`}
  ~~~   ~~~~~   ~!~~   ~~ ~  ~ ~ ~  ! ~~~~# ~~~~~~~~
                </pre>
            </Grid>

Pasting the code, using String.raw dont work either


Solution

  • The preformatted text element <pre> is suited for this purpose.

    However, this problem has a bit more complexity than just copying any given ASCII text art and then pasting it in between a JSX element's opening and closing tags.

    First, here's a code example to directly answer your question:

    body { font-family: sans-serif; }
    
    .text-art {
      background-color: hsla(0, 0%, 50%, 0.15);
      font-family: monospace;
      font-size: 1rem;
      line-height: 1;
      overflow: auto;
      padding: 1rem;
      white-space: pre;
    }
    <div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.20.11/babel.min.js"></script>
    <script type="text/babel" data-type="module" data-presets="env,react">
    
    // JSON-stringified version of your example text art
    const islandFishingTextArt = "        __ _.--..--._ _\n     .-' _/   _/\\_   \\_'-.\n    |__ /   _/\\__/\\_   \\__|\n       |___/\\_\\__/  \\___|\n              \\__/\n              \\__/       / ``_\n               \\__/    0/      `-`_\n                \\__/   |            `'-_\n             ____\\__/__|_               `'-_\n       . - '             ' -.               `-_\n      /                      \\                 `-_\n~~~~~~~  ~~~~~ ~~~~~  ~~~ ~~~  ~~~~~~~~~~~~  ~~~~~ #{`_///)__/)_.`}\n  ~~~   ~~~~~   ~!~~   ~~ ~  ~ ~ ~  ! ~~~~# ~~~~~~~~";
    
    function TextArt ({label, text}) {
      return (
        <pre
          aria-label={label}
          className="text-art"
        >{text}</pre>
      );
    }
    
    function App () {
      return (
        <div>
          <h1>ASCII Art</h1>
          <TextArt
            label="ASCII art depicting a person fishing from an island which has a single palm tree"
            text={islandFishingTextArt}
          />
        </div>
      );
    }
    
    const reactRoot = ReactDOM.createRoot(document.getElementById('root'));
    
    reactRoot.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );
    
    </script>

    In the example above, the TextArt component accepts two props: text for the ASCII text art string, and label for the accessibility description text (which becomes the value of the aria-label attribute). Accessibility can be even further improved by using a <figure> element with a <figcaption> element. Read more about this at <pre> - Accessibility Concerns.

    Here's some info on the text-art class styles:

    Note that the variable islandFishingTextArt is your text art string, but it's between double quotes and is formatted using the escape characters needed for double-quoted strings: this also makes it a JSON-compatible string.


    How can such a string be created from a raw text art string? Won't that be tedious to manually look over every character to find all of the ones that need to be escaped? That's another challenge you'll likely end up facing, so here is one suggested method:

    1. Save the raw ASCII text art as a local file. For example:

      island-fishing.art.txt:

              __ _.--..--._ _
           .-' _/   _/\_   \_'-.
          |__ /   _/\__/\_   \__|
             |___/\_\__/  \___|
                    \__/
                    \__/       / ``_
                     \__/    0/      `-`_
                      \__/   |            `'-_                                            
                   ____\__/__|_               `'-_
             . - '             ' -.               `-_    
            /                      \                 `-_     
      ~~~~~~~  ~~~~~ ~~~~~  ~~~ ~~~  ~~~~~~~~~~~~  ~~~~~ #{`_///)__/)_.`}
        ~~~   ~~~~~   ~!~~   ~~ ~  ~ ~ ~  ! ~~~~# ~~~~~~~~
      
      
    2. Since your question is about React, you're very likely to be using Node.js to build your app, so it will already be installed. Here's a Node script which will help you convert a plain text file into an ES module whose default export is a string containing the text art:

      convert-text-art.mjs:

      import {ok as assert} from 'node:assert/strict';
      import {readFile, writeFile} from 'node:fs/promises';
      
      const [inputPath, outputPath] = process.argv.slice(2);
      
      assert(inputPath, 'File input path not found');
      assert(outputPath, 'File output path not found');
      
      const encodingOpts = {encoding: 'utf-8'};
      
      const text = await readFile(inputPath, encodingOpts);
      
      const trimmed = text
        // Remove empty lines from beginning
        .replace(/^(\r?\n)+/, '')
        // Remove whitespace from end
        .trimEnd()
        // Remove whitespace from ends of lines
        .split('\n').map(line => line.trimEnd()).join('\n');
      
      const json = JSON.stringify(trimmed);
      
      const moduleSource = `export default ${json};\n`;
      
      await writeFile(outputPath, moduleSource, encodingOpts);
      
      console.log(`Text art module written to: ${outputPath}`);
      
      

      Now, you can use the Node script to convert your text art file like this in the terminal:

      % node convert-text-art.mjs island-fishing.art.txt island-fishing.art.js
      Text art module written to: island-fishing.art.js
      

      The created module contents will look like this:

      island-fishing.art.js:

      export default "        __ _.--..--._ _\n     .-' _/   _/\\_   \\_'-.\n    |__ /   _/\\__/\\_   \\__|\n       |___/\\_\\__/  \\___|\n              \\__/\n              \\__/       / ``_\n               \\__/    0/      `-`_\n                \\__/   |            `'-_\n             ____\\__/__|_               `'-_\n       . - '             ' -.               `-_\n      /                      \\                 `-_\n~~~~~~~  ~~~~~ ~~~~~  ~~~ ~~~  ~~~~~~~~~~~~  ~~~~~ #{`_///)__/)_.`}\n  ~~~   ~~~~~   ~!~~   ~~ ~  ~ ~ ~  ! ~~~~# ~~~~~~~~";
      
      
    3. Now you can either import that text art string directly from one of your React project's modules:

      import islandFishingTextArt from './island-fishing.art.js';
      

      Or just copy + paste it as a new variable (like I did in the example above), and then delete the module file that was created if you want to.

    Those steps might seem a bit involved, but I think that if you're working with multiple instances of unique text art, it'll be much easier to use a strategy like that than to manually search for and escape every problematic character. You can certainly take the idea above and refine it to work on entire directories of ASCII art text files, etc.