# Hyperlinks

Hyperlinks are workbook-local cell links. Use `univer run` to create or maintain them through the sheets hyperlink facade, then use facade readback to verify command-line results.

The hyperlink facade is available in the headless runtime through `@univerjs/sheets-hyper-link/facade`.

## Core Workflow

Look up the workbook and worksheet, build a hyperlink target, call `setHyperLink(url, label)` on the destination range, then verify with `getHyperLinks()`.

```bash
univer run ./links.univer --code 'async () => {
  const workbook = univerAPI.getActiveWorkbook();
  const sheet = workbook.getSheetByName("Sheet1");
  if (!sheet) return { success: false, error: "Sheet1 not found" };

  await sheet.getRange("A1").setHyperLink("https://univer.ai/", "Univer");

  return {
    success: true,
    links: sheet.getRange("A1").getHyperLinks()
  };
}'
```

`setHyperLink()` creates one hyperlink on the range's top-left cell. It does not create a hyperlink in every cell of a multi-cell range.

## URL Links

Use a normal URL string as the hyperlink target.

```javascript
const workbook = univerAPI.getActiveWorkbook();
const sheet = workbook.getSheetByName("Sheet1");
if (!sheet) throw new Error("Sheet1 not found");

await sheet.getRange("A1").setHyperLink("https://univer.ai/", "Univer");

const links = sheet.getRange("A1").getHyperLinks();
return links.map((link) => ({
  row: link.row,
  column: link.column,
  label: link.label,
  url: link.url
}));
```

`getHyperLinks()` returns hyperlinks found in the range. Each result includes the linked cell position, display label, and URL payload.

## Sheet Links

Use `worksheet.getUrl()` to create a sheet target. Do not hand-build `#gid` payloads; sheet ids are workbook data.

```javascript
const workbook = univerAPI.getActiveWorkbook();
const sheet = workbook.getSheetByName("Sheet1");
if (!sheet) throw new Error("Sheet1 not found");

const sheetUrl = sheet.getUrl();
await sheet.getRange("A2").setHyperLink(sheetUrl, "Go to Sheet1");

return {
  link: sheet.getRange("A2").getHyperLinks()[0],
  parsed: workbook.parseSheetHyperlink(sheetUrl)
};
```

## Range Links

Use `range.getUrl()` to create a target for a worksheet range. Do not hand-build `range` payloads.

```javascript
const workbook = univerAPI.getActiveWorkbook();
const sheet = workbook.getSheetByName("Sheet1");
if (!sheet) throw new Error("Sheet1 not found");

sheet.getRange("B2:B4").setValues([[100], [120], [90]]);

const rangeUrl = sheet.getRange("B2:B4").getUrl();
await sheet.getRange("A3").setHyperLink(rangeUrl, "Sales range");

return {
  link: sheet.getRange("A3").getHyperLinks()[0],
  parsed: workbook.parseSheetHyperlink(rangeUrl)
};
```

## Defined Name Links

Use `workbook.getUrlOfDefineName(name)` to create a hyperlink target for a defined name. The defined name must exist and its value must be a range reference.

For creating, reading, updating, deleting, and scoping defined names, see `univer help run defined-names`.

```javascript
const workbook = univerAPI.getActiveWorkbook();
const sheet = workbook.getSheetByName("Sheet1");
if (!sheet) throw new Error("Sheet1 not found");

sheet.getRange("B2:B4").setValues([[100], [120], [90]]);
workbook.insertDefinedName("SalesRange", "Sheet1!$B$2:$B$4");

const definedNameUrl = workbook.getUrlOfDefineName("SalesRange");
await sheet.getRange("A4").setHyperLink(definedNameUrl, "SalesRange");

return {
  link: sheet.getRange("A4").getHyperLinks()[0],
  parsed: workbook.parseSheetHyperlink(definedNameUrl)
};
```

If the defined name stores a formula value instead of a range reference, `getUrlOfDefineName()` fails.

```javascript
const workbook = univerAPI.getActiveWorkbook();
workbook.insertDefinedName("TotalSales", "=SUM(Sheet1!$B$2:$B$4)");

try {
  workbook.getUrlOfDefineName("TotalSales");
} catch (error) {
  return {
    success: false,
    error: error instanceof Error ? error.message : String(error)
  };
}
```

The expected error states that the defined name is not a reference range and cannot be converted to a hyperlink.

## Read, Update, And Cancel

`getHyperLinks()` reads hyperlinks in a range.

```javascript
const links = sheet.getRange("A1:A10").getHyperLinks();
```

`updateHyperLink(url, label)` updates the hyperlink on the range's top-left cell. If that top-left cell has no hyperlink, the call fails.

```javascript
await sheet.getRange("A1:B2").setHyperLink("https://example.com/old", "Old");
await sheet.getRange("A1:B2").updateHyperLink("https://example.com/new", "New");

try {
  await sheet.getRange("B1:C2").updateHyperLink("https://example.com/missing", "Missing");
} catch (error) {
  return {
    success: false,
    error: error instanceof Error ? error.message : String(error)
  };
}
```

`cancelHyperLink()` without an argument cancels hyperlinks found in the current range.

```javascript
sheet.getRange("A1:A10").cancelHyperLink();
```

Pass a hyperlink returned by `getHyperLinks()` to cancel only that link.

```javascript
const [firstLink] = sheet.getRange("A1:A10").getHyperLinks();
if (firstLink) {
  sheet.getRange("A1:A10").cancelHyperLink(firstLink);
}
```

## Parse Links

Use `workbook.parseSheetHyperlink(url)` to inspect sheet, range, and defined name targets.

```javascript
const sheetUrl = sheet.getUrl();
const rangeUrl = sheet.getRange("B2:B4").getUrl();
const definedNameUrl = workbook.getUrlOfDefineName("SalesRange");

return {
  sheet: workbook.parseSheetHyperlink(sheetUrl),
  range: workbook.parseSheetHyperlink(rangeUrl),
  definedName: workbook.parseSheetHyperlink(definedNameUrl)
};
```

Typical parsed `type` values are `gid` for sheet links, `range` for range links, `rangeid` for defined name links, and `url` for normal URLs.

## Viewer Notes

For visual inspection, open the workbook with `univer view`. `univer run` verifies hyperlink facade state; it does not simulate browser clicks or promise a screenshot of link navigation.
