---
title: "Links"
description: "Make an area of a page go to another page or open a website, and read what existing links do."
source: "https://www.embedpdf.com/docs/engine/annotations/links"
---

# Links

A link is an area of a page that does something when it's clicked: go to another page of the
document, or open a website.

```ts
await page.annotations.create({
  subtype: 'link',
  rect: { x: 72, y: 77, width: 128, height: 15 },
  target: { kind: 'uri', uri: 'https://example.com' },
});
```

A link is an area (`rect`) and what a click does (`target`). It's invisible: it has no color or
border, and PDF apps draw nothing where it is. It takes the fields every annotation has, such as
`contents` and the flags. Leave `target` out for a link that does nothing yet (`null`).

## Link to a page

A `goto` target names a page and how to show it:

```ts
const { pages } = await doc.pages.list();

await page.annotations.create({
  subtype: 'link',
  rect,
  target: { kind: 'goto', destination: { kind: 'fit', page: pages[4].ref } },
});
```

| `kind`    | What the reader sees                                         | Fields                      |
| :-------- | :----------------------------------------------------------- | :-------------------------- |
| `'fit'`   | The whole page.                                              |                             |
| `'xyz'`   | The point `x`, `y` at the top left of the window, at `zoom`. | `x`, `y`, `zoom`            |
| `'fitH'`  | The page's full width, with `y` at the top of the window.    | `y`                         |
| `'fitV'`  | The page's full height, with `x` at the left of the window.  | `x`                         |
| `'fitR'`  | The box `x`, `y`, `width`, `height`, as large as it fits.    | `x`, `y`, `width`, `height` |
| `'fitB'`  | Like `'fit'`, for the box around the page's content.         |                             |
| `'fitBH'` | Like `'fitH'`, for the box around the page's content.        | `y`                         |
| `'fitBV'` | Like `'fitV'`, for the box around the page's content.        | `x`                         |

Positions are in points on the target page, from its top-left corner, with y going down. `zoom`
is a factor: `2` shows the page at 200%. A position or zoom left out (or `null`) keeps what the
reader has, so this link scrolls to a spot without changing the zoom:

```ts
await page.annotations.update(link.ref, {
  target: {
    kind: 'goto',
    destination: { kind: 'xyz', page: pages[4].ref, x: null, y: 292, zoom: null },
  },
});
```

A link to a page the document doesn't have is refused with `NotFound`.

## Link to a website

A `uri` target opens its address, as you give it:

```ts
await page.annotations.update(link.ref, {
  target: { kind: 'uri', uri: 'https://example.com/pricing' },
});
```

## Read links

```ts
const { annotations } = await page.annotations.list();

for (const annotation of annotations) {
  if (annotation.subtype !== 'link' || !annotation.target) continue;
  const { target } = annotation;
  if (target.kind === 'goto') showPage(target.destination.page);
  if (target.kind === 'uri') openInNewTab(target.uri);
}
```

`target` says what a click does:

| `kind`          | What a click does                                  | You can create it |
| :-------------- | :------------------------------------------------- | :---------------- |
| `'goto'`        | Goes to a page of this document (`destination`).   | Yes               |
| `'uri'`         | Opens a web address (`uri`).                       | Yes               |
| `'named'`       | Runs a viewer command such as `NextPage` (`name`). | The four below    |
| `'goto-remote'` | Opens another PDF file (`file`).                   | No                |
| `'launch'`      | Opens a file or an app (`path`).                   | No                |
| `'javascript'`  | Runs a script.                                     | No                |
| `'unsupported'` | Something the engine doesn't model.                | No                |

`target: null` is a link that does nothing. A PDF can name a destination instead of spelling it
out; the engine looks the name up, so you always get an explicit `destination` with its page.

A `named` link you create runs one of the page commands every PDF app has: `NextPage`,
`PrevPage`, `FirstPage` or `LastPage`. Other names, which only some apps know, are read and kept:

```ts
await page.annotations.create({
  subtype: 'link',
  rect,
  target: { kind: 'named', name: 'NextPage' },
});
```

A new link has no border: PDF apps would otherwise draw a black line around it.

## Change or remove what a link does

```ts
await page.annotations.update(link.ref, {
  target: { kind: 'goto', destination: { kind: 'fit', page: pages[0].ref } },
});

await page.annotations.update(link.ref, { target: null }); // does nothing when clicked
```

A new target replaces the old one, and `null` removes it.

## What the engine doesn't run

Links that run a script, open another file or run another app's own command are read and kept
in the PDF as they are. The engine never runs or follows them, and you can't create them: a `target` of one
of these kinds in a create is refused with `InvalidArg`. Changing another field of such a link
(its `rect`, its `contents`) keeps what it does, and so does sending back a link you read: its
`target` stays as it was.

## Permissions

Links are annotations: they need the same permissions as any annotation. See
[Permissions](https://www.embedpdf.com/docs/engine/concepts/permissions#annotations).

## Good to know

### The full action

`target` is a simple view. The full action is in `annotation.actions` (read only). A click runs
`actions.activate`; later steps are in `next`. An action the engine can't read safely reads as
`unsupported`. Writing `target` replaces the whole action.

### Destinations and actions in the PDF

A PDF stores a link's target as a destination (`/Dest`) or as an action (`/A`). Both read as a
`goto` target; the engine writes an action. `target: null` removes both.

### Coordinates

A destination's positions are measured on the page it goes to, like that page's annotations:
from its top-left corner, with y going down. `pageDestinationOf()` and `pdfDestinationOf()`
convert to and from the PDF file's own numbers, with the crop box of the page it goes to; see
[Pages](https://www.embedpdf.com/docs/engine/documents/pages).

### Copying links

An [import](https://www.embedpdf.com/docs/engine/annotations/import-export) maps a link's destination page the way it
maps the link's own page. A link whose target the engine can't create is imported without it, and
the import reports it in `dropped` (`unsupported-action`, field `target`).
