JavaScript interoperability for Dart web and Wasm applications
The dart:js_interop library enables Dart programs to interact with JavaScript code and browser APIs. It provides a type-safe way to call JavaScript functions, access JavaScript objects, and export Dart functions to JavaScript.
JS Types - JSObject, JSArray, JSPromise, JSFunction, etc.
Primitive Types - JSNumber, JSString, JSBoolean
Type Conversions - Convert between Dart and JS types
Annotations - @JS, @staticInterop, @anonymous
Exports - Export Dart code to JavaScript
Typed Arrays - JSArrayBuffer, JSInt8Array, JSFloat64Array, etc.
This library works with both JavaScript (dart2js, DDC) and WebAssembly (dart2wasm) compilation targets, providing a unified API for JavaScript interop.
import 'dart:js_interop';// Define an interop interface for a JavaScript API@JS()extension type Window(JSObject _) implements JSObject { external Document get document; external void alert(String message); external JSPromise fetch(String url);}@JS()extension type Document(JSObject _) implements JSObject { external Element? getElementById(String id); external String get title; external set title(String value);}@JS()extension type Element(JSObject _) implements JSObject { external String get textContent; external set textContent(String value);}// Use the APIvoid updatePage() { var window = globalContext['window'] as Window; window.document.title = 'My Dart App'; var element = window.document.getElementById('content'); if (element != null) { element.textContent = 'Updated from Dart!'; }}
Marks a declaration as a JavaScript interop declaration. Can specify custom JS name.
import 'dart:js_interop';// Top-level function with JS name@JS('console.log')external void log(String message);// Class with different JS name@JS('MyJavaScriptClass')extension type MyClass(JSObject _) implements JSObject { external factory MyClass(); external void method();}// Library-level prefix@JS('myLibrary')library;import 'dart:js_interop';// All members prefixed with 'myLibrary.'@JS()external void initialize();// Calls: myLibrary.initialize()
Don’t use is checks with JS types - Use isA<T>() instead
Use == not identical for JS value comparison
Handle null and undefined - JavaScript has both, Dart only has null
Be careful with type safety - JS types are only static guarantees
Don’t rely on runtime types - They differ between JS and Wasm backends
Prefer extension types over @staticInterop classes for new code. Extension types provide better type safety and are the recommended pattern for dart:js_interop.
import 'dart:js_interop';// Check for undefined vs nullvoid handleNullish(JSAny? value) { if (value == null) { print('Value is null or undefined'); } else if (value.isUndefinedOrNull) { print('Value is nullish'); } else if (value.isDefinedAndNotNull) { print('Value exists'); }}// Type checkingvoid processUnknown(JSAny value) { if (value.typeofEquals('string')) { var str = value as JSString; print('String: ${str.toDart}'); } else if (value.typeofEquals('number')) { var num = value as JSNumber; print('Number: ${num.toDartDouble}'); }}// Instance checkingvoid checkInstance(JSAny value) { if (value.instanceOfString('Array')) { print('It\'s an array'); } else if (value.instanceOfString('Date')) { print('It\'s a date'); }}// Safe property accessextension SafeAccess on JSObject { JSAny? getProperty(String name) { try { return this[name]; } catch (e) { return null; } }}