---
title: "Блок «Страница» — ссылки на подстраницы"
description: "Однострочная ссылка на подстраницу, которую ваше приложение хранит как отдельный документ. Хуки хоста открывают, создают и обновляют страницы."
source: https://blokeditor.com/ru/docs/page/
lastmod: 2026-10-04
---

Фреймворк JavaScript

Блочные инструменты Страница

# Страница: ссылки на подстраницы

Однострочная ссылка на подстраницу, как подстраница в Notion. Показывает значок и название страницы. Каждая страница это отдельный документ, и хранит его ваше приложение. Блок сохраняет только id страницы и копию названия и значка для показа.

Blok никогда не загружает и не сохраняет страницу. Ваше приложение подключает страницы через четыре параметра конфигурации ниже.

У блока три особых состояния:

- «Новая страница»: у страницы нет названия, и вместо него видно «Новая страница». Ссылка при этом работает.
- «Страница не найдена»: `resolve` вернул `null`.
- «Нет доступа»: `resolve` вернул `{ access: 'none' }`. Сохранённое название скрыто.

Ненайденная или недоступная страница никогда не удаляется автоматически. Блок остаётся, но перестаёт работать как ссылка.

Обычный клик вызывает `open`. Enter тоже, когда блок выбран с клавиатуры. Без `open` ссылка ведёт на `href`.

Cmd/Ctrl-клик, Shift-клик и клик средней кнопкой работают как обычно в браузере, например открывают новую вкладку. Открытие в новой вкладке требует `href`. Ссылка не получает фокус, поэтому после клика отмена и Escape работают.

`page` не входит в `defaultBlockTools`. Зарегистрируйте его сами, вместе с конфигурацией.

Для HTML только для чтения вызовите `blocksToHtml(data, { pageHref })` из `@bloklabs/core/view`. Он отрисует блок как значок и название, а ссылкой блок станет, только если передать `pageHref`. Представление читает только сохранённую копию, поэтому не может показать состояния «не найдена» и «нет доступа». Тело страницы оно никогда не отрисовывает.

### Импорт

TypeScript

```
import { Page } from '@bloklabs/core/tools';
```

### Конфигурация

| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
| `href` | `(pageId: string) => string` | `undefined` | Строит URL страницы по её id. Blok ставит его на ссылку, поэтому Cmd/Ctrl-клик или клик средней кнопкой открывает страницу в новой вкладке. Без него у ссылки нет URL. Небезопасные схемы вроде `javascript:` отбрасываются. |
| `open` | `(pageId: string, ctx: { event?: MouseEvent | KeyboardEvent }) => void` | `undefined` | Открывает страницу. Blok вызывает его при обычном клике левой кнопкой. Без него клик ведёт на `href`. Enter открывает страницу и тогда, когда блок выбран с клавиатуры (Escape, затем стрелки). В этом случае `ctx.event` это нажатие клавиши. Ещё Blok вызывает его один раз сразу после того, как пользователь вставил новую страницу из тулбокса. В этом случае `ctx.event` пуст. Он не вызывается для страницы, вставленной через API, и когда `create` выбросил ошибку. |
| `resolve` | `(pageId: string) => PageInfo | null | undefined | Promise<…>` | `undefined` | Возвращает текущие название и значок страницы. Blok спрашивает один раз, когда блок отрисовывается. Можно вернуть значение или промис: `{ title, icon }`: сохранённая копия обновится, если изменилась. `null`: страницы нет. Блок покажет «Страница не найдена». `{ access: 'none' }`: этому пользователю страница недоступна. Блок покажет «Нет доступа». `undefined`: ничего не известно. Сохранённая копия остаётся. Возвращайте полную картину. Отсутствие `title` или `icon` значит, что у страницы их нет. В режиме только для чтения свежая копия показывается, но не сохраняется. Она сохранится, когда включится редактирование. Если `resolve` выбросит ошибку, сохранённая копия остаётся. |
| `create` | `(init: { pageId: string }) => void | Promise<void>` | `undefined` | Создаёт страницу в вашем приложении. Blok вызывает его один раз с id, который сгенерировал сам, когда блок страницы вставлен без `pageId`. Так бывает, когда пользователь выбирает «Страница» в тулбоксе или когда ваш код вставляет блок через API. Он никогда не вызывается при загрузке, вставке из буфера обмена, отмене, повторе, изменении от соавтора и в режиме только для чтения. Если он выбросит ошибку, блок остаётся со своим id и показывает «Страница не найдена». Blok всё равно спрашивает `resolve`, так что страница, которую ваше приложение всё-таки создало, появится. |

### Формат данных

TypeScript

```
interface PageData {
  pageId: string; // Id of the page. Blok mints one for a new page.
  cache?: {       // Display copy, refreshed from resolve(). It can be stale.
    title?: string;
    icon?: { type: 'emoji'; value: string } | { type: 'image'; url: string };
  };
}
// The page's body is NOT here. It is a separate document your app stores.
```

JSON

```
{
  "id": "pg001",
  "type": "page",
  "data": {
    "pageId": "p1",
    "cache": {
      "title": "Roadmap",
      "icon": { "type": "emoji", "value": "🗺" }
    }
  }
}
```

### Пример использования

TypeScript

```
import { Blok } from '@bloklabs/core';
import { Page } from '@bloklabs/core/tools';
import { blocksToHtml } from '@bloklabs/core/view';

const pageUrl = (pageId) => `/pages/${pageId}`;

const editor = new Blok({
  holder: 'editor',
  tools: {
    // Not in defaultBlockTools: register it with your own config.
    page: {
      class: Page,
      config: {
        href: pageUrl,
        open: (pageId) => router.push(pageUrl(pageId)),
        resolve: (pageId) => myApi.getPageInfo(pageId), // { title, icon } | null
        create: ({ pageId }) => myApi.createPage(pageId),
      },
    },
  },
});

// Read-only HTML: pass the same URL builder.
const html = blocksToHtml(savedData, { pageHref: pageUrl });
```
