Connecting the API using JavaScript
Note
Get a key for the JavaScript API package
The key is activated within 15 minutes after you receive it.
Thr JS API 3.0 works only with the keys with the "Restriction by HTTP Referer" field filled in. Learn more about the restrictions
Regular connection
<!DOCTYPE html>
<html>
<head>
<!-- Replace YOUR_API_KEY with the real key -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
{
"devDependencies": {
"http-server": "14.1.1"
},
"scripts": {
"start": "npx http-server ."
}
}
Set dependencies and run a local server:
npm install
npm run start
Open the app
Alert
The API is guaranteed to work with browsers that have an audience coverage of at least 0.5% according to Browserslist.
Specifics of regular connection
- The JS API is distributed exclusively via a link that should be inserted in the document header.
- API components are always loaded asynchronously.
- Components exist only in the global scope in the
ymaps3variable. - Components are available only after the
ymaps3.readypromise is resolved.
API loading parameters
apikey |
Required parameter The key issued in the Developer's Dashboard. Note The key is activated within 15 minutes after you receive it. Thr JS API 3.0 works only with the keys with the "Restriction by HTTP Referer" field filled in. Learn more about the restrictions |
lang |
Required parameter Locale, set as
|
ready promise
The ymaps3.ready promise guarantees that all components of the core JavaScript API module are loaded and the DOM is built.
Alert
Handlers of events like document.ready, window.onload, or jQuery.ready do not signal the end of JS API component loading.
Connecting via top-level-await (recommended)
<!DOCTYPE html>
<html>
<head>
<!-- replace YOUR_API_KEY with the real key -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script type="module" src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import { YMap, YMapDefaultSchemeLayer } from './lib/ymaps3.js'
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
await ymaps3.ready;
export const {YMap, YMapDefaultSchemeLayer} = ymaps3;
{
"devDependencies": {
"http-server": "14.1.1"
},
"scripts": {
"start": "npx http-server ."
}
}
Set dependencies and run a local server:
npm install
npm run start
Open the app
Specifics
-
Specify the
type="module"attribute in the "script" tag that loads the compiled project JS to enable ECMAScript Modules (ESM) and top-level-await support:<script type="module" src="index.js"></script>ESM support when using bundlers
If you're building a project using a bundler (for example, Webpack), add
"type": "module"topackage.json -
In
lib/ymaps3.js, wait until the JS API is fully loaded and then export the necessary map components so that they can be used in other parts of the project:await ymaps3.ready; export const {YMap, YMapDefaultSchemeLayer} = ymaps3; -
The use of top-level-await in
lib/ymaps3.jsguarantees thatymaps3.readyis executed before the map components are imported, so the project code can be shorter and cleaner (the asynchronous initMap function is no longer needed):import { YMap, YMapDefaultSchemeLayer } from './lib/ymaps3.js' const map = new YMap({...});
Connecting with Webpack
- Is there a way to not connect the JS API in the
HTMLdocument header? - Can JS API components be called not from a global variable, but more practically, as if they were delivered via an
npmpackage? - Is there a way to skip handling the
ymaps3.readypromise resolution?
You can do this using Webpack and its externals option. There are three methods, each with its own advantages and limitations.
Method 1 (without the ymaps3global variable)
<!DOCTYPE html>
<html>
<head>
<!-- replace YOUR_API_KEY with the real key -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externals: {
ymaps3: 'ymaps3'
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Set dependencies, build a project, and run a local server:
npm install
npm run build
npm run start
Open the app
Specifics
-
On the
HTMLpage, we still connect theJS APIloader:<head> <script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"></script> </head>Successful script loading guarantees that the
ymaps3variable becomes globally accessible. -
In
webpack.config.js, declare the externalymaps3variable:module.exports = { // ... externals: { ymaps3: 'ymaps3' } };This makes it possible to import
ymaps3in the project code as if theymaps3code were delivered not via a global variable, but via annpmpackage:import * as ymaps3 from 'ymaps3'; // ...
Method 2 (without the JS APIloader)
<!DOCTYPE html>
<html>
<head>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externalsType: 'script',
externals: {
// replace YOUR_API_KEY with the real key
ymaps3: ['https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US', 'ymaps3']
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Set dependencies, build a project, and run a local server:
npm install
npm run build
npm run start
Open the app
Specifics
This is a modification of the first method:
-
You no longer need to connect the
<script>tag in theHTMLdocument header —Webpackdoes this for you. -
In
webpack.config.js, you also need to declare theymaps3variable, but it should contain a path to the API loader:module.exports = { // ... externalsType: 'script', externals: { ymaps3: ['https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US', 'ymaps3'] } };
Limitations of methods 1 and 2
In both of the above methods, a lightweight loader is imported, not the ready-made API. Components become fully available only after the ymaps3.ready promise is resolved. This means that if your client code is split into modules, and the JS API is used in several of your modules at once, you should wait for the ymaps3.ready promise to be resolved in each of your modules.
For example, you want to display two maps on a page at once, each in its own container. It would be more convenient for you to describe this functionality not in a single large module, but in two different ones, for example, module-a.js and module-b.js. With the use of the above methods, the code of your modules will look something like this:
// module-a.js
import * as ymaps3 from 'ymaps3';
async function initMap() {
// Wait until `ymaps3.ready` is resolved
await ymaps3.ready;
const {YMap} = ymaps3;
// The map is initialized in the first container
const map = new YMap({document.getElementById('first-map-container')});
}
initMap();
// module-b.js
import * as ymaps3 from 'ymaps3';
async function initMap() {
// Wait until `ymaps3.ready` is resolved
await ymaps3.ready;
const {YMap} = ymaps3;
// The map is initialized in the second container
const map = new YMap({document.getElementById('second-map-container')});
}
initMap();
You have to wait for ymaps3.ready to be resolved in each module. This is not convenient, a simpler code would be more desirable:
// module-a.js
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({document.getElementById('first-map-container')});
// module-b.js
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({document.getElementById('second-map-container')});
To achieve this, use the third method.
Method 3 (without the ymaps3.readypromise resolution)
<!DOCTYPE html>
<html>
<head>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externalsType: 'script',
externals: {
// replace YOUR_API_KEY with the real key
ymaps3: [
`promise new Promise((resolve) => {
if (typeof ymaps3 !== 'undefined') {
return ymaps3.ready.then(() => resolve(ymaps3));
}
const script = document.createElement('script');
script.src = "https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US";
script.onload = () => {
ymaps3.ready.then(() => resolve(ymaps3));
};
document.head.appendChild(script);
})`
]
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Set dependencies, build a project, and run a local server:
npm install
npm run build
npm run start
Open the app
Specifics
This method is almost the same as method 2, but the path to the API loader is specified slightly differently in webpack.config.js when declaring the ymaps3 variable, and the ymaps3.ready promise is resolved there as well.
In this case, fully loaded JS API modules become available and ymaps3.ready execution is guaranteed in the built project JS file, so the project code can be shorter and cleaner:
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({...});
Alert
With this connection method, the project code will not be executed until the JS API components are fully loaded.
Limitations of method 3
Let's say you want to show a loading animation until the map components are loaded. You've connected the JS API using the third method and written the following code. Unfortunately, you will not solve the task:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ymaps3 from 'ymaps3';
// Execution of this string will start only after ymaps3 is loaded and ymaps3.ready is resolved
const reactify = ymaps3.reactify.bindTo(React, ReactDOM);
const {YMap} = reactify.module(ymaps3);
function MapView() {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
setLoading(false);
}, []);
// This code does nothing. Although it does get executed when the component is mounted in the DOM,
// mounting will be performed only after ymaps3 is loaded and ymaps3.ready is resolved.
// So when mounting, the user will see the 'Loading...' status for a split second,
// the loading animation will almost immediately be canceled by the subsequent useEffect
if (loading) {
return <div>Loading...</div>;
}
return <YMap />;
}
function App() {
return (
<MapView />
);
}
The main disadvantage of the third method of connecting Webpack is that nothing will be executed in the project modules until the JS API components are fully loaded.
Don't use it if you want to show the loading animation:
- Switch to Webpack connection method 1 or 2.
- Inside
React.useEffect, wait forymaps3.readyand only then remove theloadingflag. - The code that uses the
Reactifymodule must be placed inside theMapViewcomponent so that theJSinterpreter can read these strings only afterymaps3.readyis resolved:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ymaps3 from 'ymaps3';
function MapView() {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
ymaps3.ready.then(() => setLoading(false));
}, []);
if (loading) {
return <div>Loading...</div>;
}
const reactify = ymaps3.reactify.bindTo(React, ReactDOM);
const {YMap} = reactify.module(ymaps3);
return <YMap />;
}
function App() {
return (
<MapView />
);
}
Switching the language
Remember the language is set when connecting the API. If you are creating international websites, regardless of the connection method you are using, make sure the language is switched correctly.
For example, to connect with Webpack using the third method, you can do it as follows:
module.exports = {
//...
externals: {
ymaps3: [
`promise new Promise((resolve) => {
...
const language_region = ['tr', 'tr-TR'].includes(navigator.language) ? 'tr-TR' : 'en-US';
script.src = "https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=" + lang;
...
})`
]
}
};
Connecting packages and modules
The JS API provides additional packages and modules that can be used to solve specific tasks. To load them, use the ymaps3.import method.