---
title: "Copy Anchor Link Button"
description: "Copy anchor links to specific nodes and blocks in the Tiptap editor with keyboard shortcuts, URL generation, and accessibility support."
canonical_url: "https://tiptap.dev/docs/ui-components/components/copy-anchor-link-button"
---

# Copy Anchor Link Button

Copy anchor links to specific nodes and blocks in the Tiptap editor with keyboard shortcuts, URL generation, and accessibility support.

A fully accessible copy anchor link button for Tiptap editors. Generate and copy deep links to specific nodes or blocks in the editor with keyboard shortcut support and smart node ID detection.

> **Interactive demo:** [copy anchor link button](https://template.tiptap.dev/preview/tiptap-ui/copy-anchor-link-button)

## Installation

Add the component via the Tiptap CLI:

```bash
npx @tiptap/cli@latest add copy-anchor-link-button
```

## Components

### `<CopyAnchorLinkButton />`

A prebuilt React component that copies anchor links to nodes in the editor.

#### Usage

```tsx
export default function MyEditor() {
  return (
    <CopyAnchorLinkButton
      editor={editor}
      text="Copy Link"
      hideWhenUnavailable={true}
      showShortcut={true}
      onCopied={() => console.log('Link copied!')}
      onNodeIdNotFound={(found) => console.log(`Node ID found: ${found}`)}
      onExtractedNodeId={(nodeId) => console.log(`Extracted ID: ${nodeId}`)}
    />
  )
}
```

#### Props

| Name                  | Type                               | Default     | Description                                           |
| --------------------- | ---------------------------------- | ----------- | ----------------------------------------------------- |
| `editor`              | `Editor \| null`                   | `undefined` | The Tiptap editor instance                            |
| `text`                | `string`                           | `undefined` | Optional text label for the button                    |
| `hideWhenUnavailable` | `boolean`                          | `false`     | Hides the button when no node ID is available         |
| `onCopied`            | `() => void`                       | `undefined` | Callback fired after a successful copy operation      |
| `onNodeIdNotFound`    | `(found: boolean) => void`         | `undefined` | Called when copy operation finishes with found status |
| `onExtractedNodeId`   | `(nodeId: string \| null) => void` | `undefined` | Called after node ID is extracted                     |
| `showShortcut`        | `boolean`                          | `false`     | Shows a keyboard shortcut badge                       |

## Hooks

### `useCopyAnchorLink()`

A custom hook to build your own copy anchor link button with full control over rendering and behavior.

#### Usage

```tsx
function MyCopyAnchorLinkButton() {
  const { isVisible, handleCopyAnchorLink, canCopyAnchorLink, label, shortcutKeys, Icon } =
    useCopyAnchorLink({
      editor: myEditor,
      hideWhenUnavailable: true,
      onCopied: () => console.log('Link copied!'),
      onNodeIdNotFound: (found) => console.log(`Node ID found: ${found}`),
      onExtractedNodeId: (nodeId) => console.log(`Extracted ID: ${nodeId}`),
    })

  if (!isVisible) return null

  return (
    <button onClick={handleCopyAnchorLink} disabled={!canCopyAnchorLink} aria-label={label}>
      <Icon />
      {label}
      {shortcutKeys && <Badge>{parseShortcutKeys({ shortcutKeys })}</Badge>}
    </button>
  )
}
```

#### Props

| Name                  | Type                               | Default     | Description                                           |
| --------------------- | ---------------------------------- | ----------- | ----------------------------------------------------- |
| `editor`              | `Editor \| null`                   | `undefined` | The Tiptap editor instance                            |
| `hideWhenUnavailable` | `boolean`                          | `false`     | Hides the button when no node ID is available         |
| `onCopied`            | `() => void`                       | `undefined` | Callback fired after a successful copy operation      |
| `onNodeIdNotFound`    | `(found: boolean) => void`         | `undefined` | Called when copy operation finishes with found status |
| `onExtractedNodeId`   | `(nodeId: string \| null) => void` | `undefined` | Called after node ID is extracted                     |

#### Return Values

| Name                   | Type            | Description                                            |
| ---------------------- | --------------- | ------------------------------------------------------ |
| `isVisible`            | `boolean`       | Whether the button should be rendered                  |
| `canCopyAnchorLink`    | `boolean`       | If an anchor link can be copied for the current node   |
| `handleCopyAnchorLink` | `() => boolean` | Function to copy the anchor link for the selected node |
| `label`                | `string`        | Accessible label text for the button                   |
| `shortcutKeys`         | `string`        | Keyboard shortcut for copying anchor links             |
| `Icon`                 | `React.FC`      | Icon component for the copy button (LinkIcon)          |

## Utilities

### `canCopyAnchorLink(editor)`

Checks if a node has a data-id that can be copied in the current editor state.

```tsx
import { canCopyAnchorLink } from '@/components/tiptap-ui/copy-anchor-link-button'

const canCopy = canCopyAnchorLink(editor)
```

### `copyNodeId(editor, onExtractedNodeId, onNodeIdNotFound)`

Programmatically extracts and copies the node ID to clipboard with full URL.

```tsx
import { copyNodeId } from '@/components/tiptap-ui/copy-anchor-link-button'

const success = await copyNodeId(
  editor,
  (nodeId) => console.log(`Extracted: ${nodeId}`),
  (found) => console.log(`Found: ${found}`),
)
if (success) {
  console.log('Anchor link copied successfully!')
}
```

### `extractNodeId(node, attributeName)`

Extracts the data-id from a specific node.

```tsx
import { extractNodeId } from '@/components/tiptap-ui/copy-anchor-link-button'

const nodeId = extractNodeId(node, 'data-id')
```

### `shouldShowButton(props)`

Utility to determine if the copy anchor link button should be visible based on editor state and configuration.

```tsx
import { shouldShowButton } from '@/components/tiptap-ui/copy-anchor-link-button'

const shouldShow = shouldShowButton({
  editor,
  hideWhenUnavailable: true,
})
```

## Keyboard Shortcuts

The copy anchor link button supports the following keyboard shortcut:

- **Cmd/Ctrl + Ctrl + L**: Copy the anchor link for the current node

The shortcut is automatically registered when using either the `<CopyAnchorLinkButton />` component or the `useCopyAnchorLink()` hook. This shortcut works with any block-level node that has a unique ID including paragraphs, headings, blockquotes, and code blocks.

## How It Works

The copy anchor link functionality works by:

1. **Node ID Detection**: Automatically detects nodes with unique IDs (typically using a `data-id` attribute)
2. **URL Generation**: Creates a full URL with the current page URL plus a hash fragment pointing to the node ID
3. **Clipboard Integration**: Uses the native clipboard API to copy the generated URL
4. **Source Tracking**: Adds a `source=copy_link` query parameter for analytics

The generated URL format is: `https://example.com/page?source=copy_link#node-id`

## Requirements

### Dependencies

- `@tiptap/react` - Core Tiptap React integration
- `@tiptap/pm` - ProseMirror core functionality
- `react-hotkeys-hook` - Keyboard shortcut management

### Referenced Components

- `use-tiptap-editor` (hook)
- `use-mobile` (hook)
- `button` (primitive)
- `badge` (primitive)
- `tiptap-utils` (lib)
- `tiptap-advanced-utils` (lib)
- `link-icon` (icon)

### Extensions Required

This component works best with the UniqueID extension that automatically assigns unique identifiers to nodes. The extension can be configured with a custom attribute name (defaults to `data-id`).
