# Configure hyperlink behavior

> Keep SuperDoc's defaults, suppress activation, or handle one hyperlink activation in your application.



By default, SuperDoc opens the built-in editor when a hyperlink can be edited and follows the link when it cannot.
Configure activation only when your application needs different behavior.

## Try hyperlink activation [#try-hyperlink-activation]

Expand the Editor, then click **SuperDoc documentation** after each change:

1. **Default** opens the built-in hyperlink editor in Editing mode.
2. **Do nothing** suppresses activation.
3. **Custom action** renders an action from your application beside the hyperlink.

> **Interactive editor: Try hyperlink activation**
>
> Sample: [open the fixture](/fixtures/hyperlinks-sample.docx).
>
> Preset: `hyperlinks`.
>
> Hyperlink behaviors available in the interactive Editor:
>
> - **Default:** SuperDoc opens its built-in hyperlink editor in Editing and Suggesting modes.
> - **Do nothing — `hyperlinks: false`:** activation has no effect.
> - **Custom action — `hyperlinks.onActivate`:** your application renders an action beside the hyperlink.
>
> The fixture contains one real external hyperlink. Changing the behavior recreates the Editor from its current DOCX.
>
> Local DOCX selection: disabled.


Changing the behavior reloads the current DOCX because `hyperlinks` is a startup option. Document edits remain; the
open hyperlink surface and selection reset.

## Keep the mode-aware default [#keep-the-mode-aware-default]

Omit `hyperlinks` when SuperDoc should choose the behavior from the document mode:

| Document mode | Default activation                      |
| ------------- | --------------------------------------- |
| Editing       | Open the built-in hyperlink editor.     |
| Suggesting    | Open the built-in hyperlink editor.     |
| Viewing       | Navigate to the URL or document anchor. |

Links outside editable text, such as linked images and links in headers or footers, navigate in every mode.

Set `hyperlinks: false` when activation should do nothing in every mode.

## Render a custom action [#render-a-custom-action]

Use `hyperlinks.onActivate` when your application should decide what happens for one activation. Create
`src/hyperlink-activation.ts` with a small DOM surface for open and close actions:

```ts
import type { HyperlinkActivationHandler } from 'superdoc';

const SAFE_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);
const HAS_PROTOCOL = /^[a-z][a-z0-9+.-]*:/i;

function getSafeHref(rawHref: string) {
  const href = rawHref.trim();
  if (!href) return null;
  if (href.startsWith('#')) return href;

  const candidate = HAS_PROTOCOL.test(href) ? href : `https://${href}`;

  try {
    return SAFE_PROTOCOLS.has(new URL(candidate).protocol) ? candidate : null;
  } catch {
    return null;
  }
}

export const handleHyperlinkActivation: HyperlinkActivationHandler = ({ href }) => {
  const safeHref = getSafeHref(href);
  if (!safeHref) return { type: 'none' };

  return {
    type: 'render',
    render: ({ container, close }) => {
      const panel = document.createElement('div');
      const link = document.createElement('a');
      const closeButton = document.createElement('button');

      link.href = safeHref;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.textContent = 'Open hyperlink';

      closeButton.type = 'button';
      closeButton.textContent = 'Close';
      closeButton.addEventListener('click', close);

      panel.append(link, closeButton);
      container.append(panel);

      return {
        destroy() {
          closeButton.removeEventListener('click', close);
          panel.remove();
        },
      };
    },
  };
};

```

Add the handler to the `/sample.docx` project from the [Quickstart](/editor/quickstart):

**Vanilla — `src/main.ts`**

```ts
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';
import { handleHyperlinkActivation } from './hyperlink-activation';

const superdoc = new SuperDoc({
  selector: '#editor',
  document: '/sample.docx',
  hyperlinks: {
    onActivate: handleHyperlinkActivation,
  },
  ui: {
    toolbar: { container: '#toolbar', groups: { center: ['link'] } },
  },
});

window.addEventListener('beforeunload', () => superdoc.destroy());

```

**React — `src/App.tsx`**

```tsx
import { SuperDocEditor, type SuperDocEditorProps } from '@superdoc/react';
import '@superdoc/react/style.css';
import { handleHyperlinkActivation } from './hyperlink-activation';

const editorConfig = {
  hyperlinks: {
    onActivate: handleHyperlinkActivation,
  },
  ui: {
    toolbar: { groups: { center: ['link'] } },
  },
} satisfies Pick<SuperDocEditorProps, 'hyperlinks' | 'ui'>;

export default function App() {
  return <SuperDocEditor document='/sample.docx' hyperlinks={editorConfig.hyperlinks} ui={editorConfig.ui} />;
}

```


Vanilla also needs separate toolbar and Editor mounts:

```html
<div id="toolbar"></div>
<div id="editor"></div>

<script type="module" src="/src/main.ts"></script>

```

Return `{ type: 'default' }` to use SuperDoc's default for that activation or `{ type: 'none' }` to suppress it. The
render callback receives an empty positioned `container` and a `close()` function. Return `destroy()` when the
application adds listeners or mounts a framework root.

The context includes the `href`, current `documentMode`, and `defaultAction`. The default action is `edit` when SuperDoc
can edit the link and `navigate` otherwise.

`onActivate` must return synchronously. Code it starts may continue asynchronously. From that code, call
`await context.getDocumentTarget()` to get the exact `HyperlinkTarget` to pass as `target` to
`editor.doc.hyperlinks.get()`, `patch()`, or `remove()`. It returns `null` when SuperDoc cannot match the activated link
to a Document API hyperlink.

If `onActivate` throws, returns a Promise, returns an invalid result, or its render callback throws, SuperDoc suppresses
the activation and reports the failure through `onException`.

## Choose the right extension point [#choose-the-right-extension-point]

Use `onActivate` for work tied to one activation: analytics, application routing, suppression, or a small anchored
action. Use [Custom UI](/editor/custom-ui/overview) for a persistent toolbar, sidebar, or dialog and for complete
insert, edit, and remove workflows. An `onActivate` handler can open that custom UI.

Use the [Document API hyperlink reference](/document-api/reference/hyperlinks) when code needs to list, create, update,
or remove hyperlinks without a visual interaction.
