:::meta
description: The tern object in node and in the browser: parse, transform, emit, toHTML, check, visit, outline, the schema registry, the runtime API and its events, tern.config, the lifecycle, and the AST with its data.tern fields.
:::
::site-nav
# JavaScript API {#top}
::toc
Everything Tern does is on one object, `tern`. In a browser it is `window.tern`; under node it is what `require('./tern.js')` returns. It has two halves:
- **The engine** turns a note's source into an AST, computes its semantics and writes HTML. It is pure: no DOM, no I/O, the same output in node and in every browser.
- **The runtime** renders a note in the page, runs DOM behaviours and fires events. It exists only in a browser. Under node its members are present but do nothing.
This page is the reference for both, for the order in which the runtime does things, and for the AST the engine produces. The [Guide](guide.html#top) is the gentler introduction, and [Vocabulary and behaviour](schema.html#top) explains schemas, add-ons and behaviours with worked examples.
| Member | Half | What it does | Under node |
|---|---|---|---|
| [`tern.parse(source, opts)`](#parse) | engine | source → `{ast, diagnostics}` | works |
| [`tern.transform(ast, opts)`](#transform) | engine | ids, numbers, labels, references, toc, in place | works |
| [`tern.transform(name, fn, where)`](#registering-a-transform) | engine | adds a transform | works |
| [`tern.emit(ast, opts)`](#emit) | engine | AST → HTML string | works |
| [`tern.toHTML(source, opts)`](#tohtml) | engine | parse, transform and emit, synchronously | works |
| [`tern.check(source, opts)`](#check) | engine | every diagnostic of a note | works |
| [`tern.visit(tree, type, fn)`](#visit) | engine | walks a tree | works |
| [`tern.outline(ast)`](#outline) | engine | the editor digest | works |
| [`tern.search`](#search) | engine | entries, an index and a ranked query over notes; a note's description for a catalogue | works |
| [`tern.schema`](#registry) | engine | the vocabulary, as plain data | works |
| [`tern.block`, `tern.leaf`, `tern.inline`](#registry) | engine | declare a name | works |
| [`tern.transforms`](#tern-transforms) | engine | the transform order | works |
| [`tern.css`](#tern-css) | engine | the base stylesheet, as a string | works |
| [`tern.version`](#tern-version) | engine | `'0.6.0'` | works |
| [`tern.define`, `tern.undefine`](#define) | runtime | DOM behaviours | registers; nothing runs |
| [`tern.on(event, fn)`](#on) | runtime | `render`, `math`, `ready`, `diagnostic` | registers; nothing fires |
| [`tern.render(root, source)`](#render) | runtime | renders into an element | resolves to `[]` |
| [`tern.ready`](#ready) | runtime | a Promise | never settles |
| [`tern.diagnostics`](#diagnostics) | runtime | the page's diagnostics | stays `[]` |
| [`tern.config`](#config) | runtime | `window.TERN` and the tag's `data-*` | `{use: {}}` |
| [`tern.style(css)`](#style) | runtime | adds a stylesheet | does nothing |
## Loading {#loading}
### In a browser {#in-a-browser}
A note's first line loads tern.js:
```html
```
When tern.js runs from that tag, it defines `window.tern` and starts the runtime. The runtime takes the rest of the file as the note, renders it in place and fires its events ([the lifecycle](#lifecycle)). So code that runs after that line finds `tern` as a global: the add-ons listed in `data-use`, and the `
```
With `defer`, tern.js still warns once in the console that the note was not rendered; inserting the script yourself does not.
### `tern.ready` {#ready}
:::syntax
```js
tern.ready → Promise
```
:::
A Promise that resolves, with no value, right after the `ready` listeners have run. It never rejects. Unlike `tern.on('ready')`, it works whenever you await it, before or after the event.
```js
await tern.ready;
document.querySelectorAll('main.tern .t-math .katex').length; // the typeset formulas
```
It never settles under node, nor on a page where the runtime did not start ([When nothing starts](#no-start)).
### `tern.diagnostics` {#diagnostics}
The page's diagnostics, in one array that stays the same object for the life of the page: hold a reference and it stays current.
- **At mount** it holds, sorted by position:
- the runtime diagnostics found before the mount, at line 0, which therefore come first: [`doc.quirks`](diagnostics.html#doc-quirks), and [`addon.failed`](diagnostics.html#addon-failed) for an add-on that did not load or threw while it ran;
- the note's parse and transform diagnostics, as [`tern.check`](#check) returns them, including `addon.failed` for a registered transform that threw.
- **Later** runtime diagnostics are appended as they happen: [`script.document-write`](diagnostics.html#script-document-write) and [`script.domcontentloaded`](diagnostics.html#script-domcontentloaded) while the note's scripts run. (The engine renders no math, so a math add-on reports a formula it cannot typeset to the console, not here.) They concern the page's note: one about an element that another `tern.render(root, source)` call rendered only fires the event. Each diagnostic the runtime reports itself, early or late, also fires the [`diagnostic`](#on) event; those of the parse and the transforms do not.
- **`tern.render(main, source)`** replaces the contents with the new note's diagnostics, keeping the line-0 ones.
- **On a built page** it holds the build's diagnostics, read from the page, then an `addon.failed` for each add-on script that failed to load or threw while it ran.
Each entry has the [shape of a diagnostic](#check). The runtime's four codes are all errors:
| Code | Position | Reported when |
|---|---|---|
| [`doc.quirks`](diagnostics.html#doc-quirks) | line 0 | the file has no ``, so the page is in quirks mode, where the layout and some add-ons misbehave |
| [`addon.failed`](diagnostics.html#addon-failed) | line 0 | a `data-use` or `:::use` entry did not load; a script add-on threw while it ran (the note renders with what it registered before the error); a registered transform threw |
| [`script.document-write`](diagnostics.html#script-document-write) | the `
```
On that page, once tern.js has started:
```js
tern.config;
// → { use: { katex: { macros: { '\\R': '\\mathbb{R}' } },
// theorems: { labels: 'de' }, theme: { dark: '' } },
// lang: 'en', nonce: 'abc', diagnostics: false, quiet: false }
```
- **When.** `tern.config` is filled once, when tern.js starts. So `window.TERN` must be set by a script in the head, before the tern.js line; setting it later does nothing.
- **What is copied.** Every key of `window.TERN` is copied into `tern.config`, including keys Tern does not use. An add-on can read its own settings from there.
- **`addonTimeout`** (milliseconds, 12 000 by default) is how long the mount waits for an add-on still loading once the note has arrived ([Waiting](#capture)).
- **`holdOver`** (characters, 200 000 by default) is the note size from which the mount holds the top-level blocks out of view with `content-visibility: auto`, so a long note paints its first screen without laying out the rest ([Performance](publishing.html#performance)); `0` never holds.
- **Booleans.** For `data-diagnostics` and `data-quiet`, the values `false`, `0`, `off` and `no` (in any case) mean false; any other value, or none, means true. Without the attribute, the `window.TERN` value counts, and false when it has none.
| `window.TERN` | Attribute | `tern.config` | Value |
|---|---|---|---|
| `use` | `data-use` | `use` | the add-ons' options, a math add-on's among them (`use.katex` for [`katex.js`](addons.html#katex)). Each add-on entry's query string, in `data-use` or `:::use`, goes to `use[NAME]`, where NAME is the file name without `.min` and `.js`, `.mjs` or `.css`: `theorems.js?labels=de` gives `use.theorems.labels === 'de'`, and a key without a value is `''`. The query wins over a `window.TERN.use[NAME]` key of the same name |
| `schema` | | `schema` | the note's own vocabulary, `{block, leaf, inline}` in the registry's shape, applied at mount after the add-ons ([`window.TERN.schema`](schema.html#window-tern)). Its `strict` sets `tern.schema.strict`, over an add-on's |
| `css` | `data-css` | `css` | a stylesheet to use as the base instead of the inline one ([CSP](publishing.html#csp)) |
| `nonce` | `data-nonce` | `nonce` | a CSP nonce, set on every `style`, `link` and `script` Tern adds, and on the note's re-created scripts |
| `lang` | `data-lang` | `lang` | the label language. After mount, when nothing set it, it is the `lang` of `` (which `:::meta` may have set). The command line picks labels in the same order: `data-lang`, `window.TERN.lang`, the `lang` of `:::meta`, then `` |
| `diagnostics` | `data-diagnostics` | `diagnostics` | true shows the panel everywhere, not only on `file:` and `localhost` |
| `quiet` | `data-quiet` | `quiet` | true hides the panel everywhere; it wins over `diagnostics` |
| any other key | | the same key | copied as it is |
**`data-use`** is also how add-ons are loaded. Its value is a list of URLs, separated by spaces, resolved against the page; a [`:::use` block](syntax-blocks.html#use) at the top of the note lists more, one or more per line, loaded after the tag's. An entry ending in `.css` (before its query) is a stylesheet, linked in its place in the [cascade](#style); any other is a script. Scripts are fetched in parallel and run in the order listed, and the note mounts only once every entry has loaded or failed.
**KaTeX options.** The [`katex.js` add-on](addons.html#katex) reads `tern.config.use.katex` and passes every key except `displayMode` and `throwOnError` to KaTeX: `macros`, `trust`, `strict`, `output`, `leqno` and the rest. `throwOnError` is always true, so a formula KaTeX rejects keeps its TeX, and the add-on warns in the console rather than reporting a diagnostic. `macros` is copied into one table that every formula shares; the `:::macros` blocks of the note are defined into it first. A copy of KaTeX of your own is `addons/katex.js?base=URL`, not a config key.
Two other attributes belong to the tag but not to `tern.config`. `data-built` marks a page written by `tern build` (always just `data-built`, with no value; [A built page](#built-page)). `src` must name a file called `tern.js` for editors and the command line to [detect the note](tools.html#detection).
An add-on reads its options like this:
```js
// theorems.js, listed as data-use="theorems.js?labels=de"
const opts = tern.config.use.theorems || {}; // → { labels: 'de' }
```
### `tern.style` {#style}
:::syntax
```js
tern.style(css) → HTMLStyleElement
```
:::
Adds a stylesheet to the head and returns its `