Import maps bring order to browser-based ES modules

ES modules have given web developers a standard way to structure and reuse JavaScript code. The remaining friction point has been the messy syntax and resolution logic required when importing bare module specifiers directly in the browser. With import maps, that friction is now gone: the feature has reached cross-browser support in all major engines.

Import maps are defined via the <script type="importmap"> tag in your HTML. Inside the tag, a JSON object maps human-friendly module names to their actual URLs. In the <head> of your document, the mapping might look like this:

<script type="importmap">
  {
    "imports": {
      "browser-fs-access": "https://unpkg.com/[email protected]/dist/index.modern.js"
    }
  }
</script>

This snippet maps the name "browser-fs-access" to the library's URL on the unpkg CDN. Once defined, the specifier becomes a usable import target inside any module script. Note that the import keyword is reserved for <script type="module"> blocks:

<button>Select a text file</button>
<script type="module">
  import {fileOpen} from 'browser-fs-access';

  const button = document.querySelector('button');
  button.addEventListener('click', async () => {
    const file = await fileOpen({
      mimeTypes: ['text/plain'],
    });
    console.log(await file.text());
  });
</script>

Why this is an improvement

The pre-import-map approach required developers to use full or relative URLs in every import statement, or to rely on a bundler to rewrite bare specifiers during the build. Import maps move that resolution logic into the browser, and keep the dependency mapping in one declarative place rather than scattered across your JavaScript files.

At runtime, checking whether a browser supports import maps is straightforward:

if (HTMLScriptElement.supports('importmap')) {
  // The importmap feature is supported.
}

The feature is now supported by Chrome and Edge from version 89, Firefox from version 108, and Safari from version 16.4.