# Hyperlinks: Insert > Link and HYPERLINK

Excel's two ways of putting a link in a cell. Insert > Link (Ctrl+K) puts one ON the cell, so editing the text keeps it and clearing the cell takes it away; the HYPERLINK function puts one in a formula with a friendly name. A target that reads like an address moves the selection instead of leaving the page, so a cell links to another sheet; anything with a scheme opens in a new tab. A single click follows, a drag selects. Links ride in getState(), move with an insert, and go into the .xlsx both ways.

Requires `@svgrid/enterprise` (and `@svgrid/grid`). Category: Spreadsheet. Live demo: https://svgrid.com/demos/489-sheet-hyperlinks/

Install: `npm i @svgrid/grid @svgrid/enterprise` (Svelte 5).

## About this example

Excel's two ways of putting a link in a Svelte 5 spreadsheet cell. Insert > Link, or Ctrl+K, puts a link ON the cell: the cell keeps whatever it says and the link is kept beside it, so editing the text keeps the link and clearing the cell takes it away. The HYPERLINK function puts one in a formula, showing a friendly name. A target that reads like an address moves the selection instead of leaving the page, so a cell can link to another sheet; anything with a scheme opens in a new tab. A single click follows, a drag selects. Links ride in getState(), move with an insert or a delete, and go into the .xlsx both ways. Enterprise, in @svgrid/enterprise.

Excel's two ways of putting a link in a cell, both here.

```text
Insert > Link (Ctrl+K)  a link ON the cell: the cell keeps whatever
                        it says, and the link is kept beside it. Edit
                        the text and the link stays; clear the cell
                        and it goes. This is what column C uses.
=HYPERLINK(url, name)   a link IN a formula, which shows the friendly
                        name. Column E uses it, built from the ticket
                        id beside it.
```

A target that reads like an address moves the selection instead of leaving the page: the Owner column links to the People sheet, so clicking one goes there. Anything with a scheme, or a bare www., opens in a new tab. A single click follows the link, a drag from the same cell selects, which is Excel's rule.

Links ride in `getState()` under `links`, move with an insert or a delete, and go into the .xlsx as real hyperlinks, an external one as a relationship and an internal one as a location, both read back.

Try: click a ticket in C, then an owner in B. Press Ctrl+K on a cell to add or edit a link, and Insert > Remove to take one off. Insert a row above 2 and watch the links move with their rows. File > Save As, and open the file in Excel.

## Imports, features and API used

- Imports: `@svgrid/enterprise`

## Frequently asked questions

### Is the link on the text or on the cell?

On the cell, the way Excel keeps one. The cell holds whatever was typed and the link sits beside it, so editing the text keeps the link, a format change keeps it, saving keeps it, and clearing the cell takes it away. The HYPERLINK function is the other way, a link that lives in the formula.

### Can a link go to another sheet?

Yes. A target that reads like an address, Sheet2!B4 or B4 or a defined name, moves the selection there instead of leaving the page, switching sheets if it has to. Anything with a scheme, or a bare www., opens in a new tab.

### Do links survive a save?

Yes, in both directions. An external link is written as a relationship with TargetMode External, which is what Excel writes, and an internal one as a location on the hyperlink element; a file opened back carries both, tooltips included.

## Related documentation

- [The spreadsheet shell](https://svgrid.com/docs/help/cells/spreadsheet-shell.md)

## Related articles

- [A Fill Handle (Drag to Fill) in SvGrid](https://svgrid.com/blog/fill-handle-drag-to-fill/) - Build a working spreadsheet-style fill handle on top of SvGrid's cell selection and editing - pointer tracking, range highlighting, series fill, and undo/redo integration all covered.
- [Pivot Tables in Svelte - Summarize Data Without a Spreadsheet](https://svgrid.com/blog/pivot-tables/) - Run a cross-tab pivot directly inside your Svelte app using @svgrid/enterprise createPivotModel - no Excel, no server-side aggregation, no stale exports.
- [Spreadsheet-Style Cell Range Selection in SvGrid](https://svgrid.com/blog/cell-range-selection/) - How to enable drag-to-select cell ranges, read live selection state, and build a status-bar footer that sums and averages the selected values.

## Source code (489-sheet-hyperlinks.svelte)

```svelte
<script lang="ts">
  /**
   * 489. Hyperlinks: Insert > Link and the HYPERLINK function
   * ---------------------------------------------------------
   * Excel's two ways of putting a link in a cell, both here.
   *
   *   Insert > Link (Ctrl+K)  a link ON the cell: the cell keeps whatever
   *                           it says, and the link is kept beside it. Edit
   *                           the text and the link stays; clear the cell
   *                           and it goes. This is what column C uses.
   *   =HYPERLINK(url, name)   a link IN a formula, which shows the friendly
   *                           name. Column E uses it, built from the ticket
   *                           id beside it.
   *
   * A target that reads like an address moves the selection instead of
   * leaving the page: the Owner column links to the People sheet, so
   * clicking one goes there. Anything with a scheme, or a bare www., opens
   * in a new tab. A single click follows the link, a drag from the same
   * cell selects, which is Excel's rule.
   *
   * Links ride in `getState()` under `links`, move with an insert or a
   * delete, and go into the .xlsx as real hyperlinks, an external one as a
   * relationship and an internal one as a location, both read back.
   *
   * Try: click a ticket in C, then an owner in B. Press Ctrl+K on a cell to
   * add or edit a link, and Insert > Remove to take one off. Insert a row
   * above 2 and watch the links move with their rows. File > Save As, and
   * open the file in Excel.
   */
  import { SvSheet, createWorkbook, createSheetDocument } from '@svgrid/enterprise'

  const tickets = [
    { id: 'SG-1041', title: 'Frozen panes drift on zoom', owner: 'Ada', status: 'Open' },
    { id: 'SG-1042', title: 'Paste from Excel loses italics', owner: 'Grace', status: 'Open' },
    { id: 'SG-1043', title: 'CSV export quotes twice', owner: 'Linus', status: 'Closed' },
    { id: 'SG-1044', title: 'Sparkline colours ignore the theme', owner: 'Ada', status: 'Open' },
    { id: 'SG-1045', title: 'Name Box refuses a sheet-qualified ref', owner: 'Grace', status: 'Open' },
  ]

  const rows: string[][] = [
    ['Id', 'Owner', 'Title', 'Status', 'On the tracker'],
    ...tickets.map((t, i) => [
      t.id,
      t.owner,
      t.title,
      t.status,
      `=HYPERLINK("https://example.com/issues/" & A${i + 2}, "Open " & A${i + 2})`,
    ]),
  ]

  const people: string[][] = [
    ['Person', 'Team', 'Open tickets'],
    ['Ada', 'Grid', '=COUNTIFS(Tickets!B2:B6, A2, Tickets!D2:D6, "Open")'],
    ['Grace', 'Sheet', '=COUNTIFS(Tickets!B2:B6, A3, Tickets!D2:D6, "Open")'],
    ['Linus', 'Platform', '=COUNTIFS(Tickets!B2:B6, A4, Tickets!D2:D6, "Open")'],
  ]

  const wb = createWorkbook([
    { name: 'Tickets', cells: rows },
    { name: 'People', cells: people },
  ])
  const doc = createSheetDocument({ workbook: wb })
  const at = { rowIdAt: (i: number) => `r${i}`, columnIdAt: (i: number) => String.fromCharCode(65 + i) }

  const sheet = doc.get('Tickets')
  sheet.formats.set([[0, 0, 0, 4]], { bold: true, fill: '#e2e8f0', color: '#0f172a' }, at)
  sheet.widths.A = 90
  sheet.widths.B = 90
  sheet.widths.C = 260
  sheet.widths.E = 150
  sheet.freeze = { rows: 1, cols: 0 }

  // Column C: a link on each title, out to the tracker. Column B: a link to
  // the person on the other sheet, which moves the selection rather than
  // leaving the page.
  sheet.links = Object.fromEntries(tickets.map((t, i) => [
    `r${i + 1}`,
    {
      C: { target: `https://example.com/issues/${t.id}`, tip: `${t.id} on the tracker` },
      B: { target: `People!A${['Ada', 'Grace', 'Linus'].indexOf(t.owner) + 2}`, tip: `${t.owner} on the People sheet` },
    },
  ]))

  const peopleSheet = doc.get('People')
  peopleSheet.formats.set([[0, 0, 0, 2]], { bold: true, fill: '#e2e8f0', color: '#0f172a' }, at)
  peopleSheet.widths.A = 110
  peopleSheet.widths.B = 110
  peopleSheet.widths.C = 110
  // And back the other way: each person links to the ticket list.
  peopleSheet.links = {
    r1: { A: { target: 'Tickets!A1', tip: 'Back to the tickets' } },
    r2: { A: { target: 'Tickets!A1', tip: 'Back to the tickets' } },
    r3: { A: { target: 'Tickets!A1', tip: 'Back to the tickets' } },
  }
</script>

<SvSheet document={doc} height="100%" rows={16} columns={8} />
```

[View this example on GitHub](https://github.com/sv-grid/sv-grid/blob/main/examples/src/demos/489-sheet-hyperlinks.svelte)
