JavaScript modules
ES modules split code into explicit imports and exports. Their static structure improves organization, tooling, and tree shaking compared with older module patterns.
Overview
ES modules split code into explicit imports and exports. Their static structure improves organization, tooling, and tree shaking compared with older module patterns.
Browser support
| Feature | Desktop | Mobile | ||||
|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Safari iOS | |
| 61 | 16 | 60 | 10.1 | 61 | 10.3 | |
| HTML attribute | ||||||
nomodule | 61 | 16 | 60 | 11 | 61 | 11 |
| DOM API | ||||||
ecmascript_modules Support for ECMAScript modules | 80 | 80 | 114 | 15 | 80 | 15 |
| Other | ||||||
html.elements.script.type.module `type="module"` | 61 | 79 | 60 | 10.1 | 61 | 10.3 |
| The import() syntax, commonly called dynamic import, is a function-like expression that allows loading an ECMAScript module asynchronously and dynamically into a potentially non-module environment. | 63 | 79 | 67 | 11.1 | 63 | 11.3 |
| The import.meta meta-property exposes context-specific metadata to a JavaScript module. It contains information about the module, such as the module's URL. | 64 | 79 | 62 | 11.1 | 64 | 12 |
| Operator | ||||||
| import.meta.resolve() is a built-in function defined on the import.meta object of a JavaScript module that resolves a module specifier to a URL using the current module's URL as base. | 105 | 105 | 106 | 16.4 | 105 | 16.4 |
| Statement | ||||||
arbitrary module namespace identifier names Arbitrary module namespace identifier names | 88 | 88 | 87 | 14.1 | 88 | 14.5 |
default `default` keyword with `export` | 61 | 16 | 60 | 10.1 | 61 | 10.3 |
namespace `export * as namespace` | 72 | 79 | 80 | 14.1 | 72 | 14.5 |
| Other | ||||||
| The static import declaration is used to import read-only live binding which are exported by another module. The imported bindings are called live bindings because they are updated by the module that exported the binding, but cannot be re-assigned by the importing module. | 61 | 16 | 60 | 10.1 | 61 | 10.3 |
| Statement | ||||||
arbitrary module namespace identifier names Arbitrary module namespace identifier names | 88 | 88 | 87 | 14.1 | 88 | 14.5 |
| The import attributes feature instructs the runtime about how a module should be loaded, including the behavior of module resolution, fetching, parsing, and evaluation. It's supported in import declarations, export...from declarations, and dynamic import(). | 123 | 123 | 138 | 17.2 | 123 | 17.2 |
worklet support Available in worklets | | | 114 | | | |
| Other | ||||||
svg.elements.script.type.module Experimental `type='module'` | | | 117 | | | |
- Nested workers support was introduced in Safari 15.5.
- Script loading in nested workers was introduced in Safari 16.4.
- Nested workers support was introduced in Safari on iOS 15.5.
- Script loading in nested workers was introduced in Safari on iOS 16.4.
- Module scripts without the `async` attribute do not load when the page is served as XHTML (`application/xhtml+xml`). See bug 40518469.
- Module scripts without the `async` attribute do not load when the page is served as XHTML (`application/xhtml+xml`). See bug 40518469.
- This feature was removed in a later browser version (79)
- Module scripts do not load when the page is served as XHTML (`application/xhtml+xml`).
- Module scripts without the `async` attribute do not load when the page is served as XHTML (`application/xhtml+xml`). See bug 40518469.
- Module scripts do not load when the page is served as XHTML (`application/xhtml+xml`).
Syntax
// Export
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default class Calculator { ... }
// Import
import Calculator, { PI, add } from './math.js';
import * as math from './math.js'; Use cases
Separating concerns
Move formatting, state, networking, and UI helpers into clear modules with explicit boundaries.
Optimized bundles
Static imports help bundlers remove unused code and understand dependency graphs more effectively.
Cautions
- Circular dependencies can produce confusing runtime states, so keep module boundaries intentional.
- Module organization should serve clarity, not create many tiny files with weak separation.
Accessibility
- A well-structured module system makes focus management, labeling, and announcement logic easier to keep consistent across a UI.
Related links
Powered by web-features