Skip to main content
Custom blocks are in private alpha:
  • Do not discuss publicly or share with anyone outside your workspace.
  • Access must be enabled per workspace. Installing the SDK does not grant access.
  • These APIs may experience breaking changes without notice.
App context is what the host tells the block about where it is running. All of it arrives in the init payload and stays current for the life of the block.

API overview

Each context value has a getter, a subscription, and a React hook. Use a getter to read the current value once. Use a subscription to receive the initial value and later changes. In React, use a hook to keep a component current as the value changes. The getters and subscriptions below are methods on customBlock, imported from @notionhq/custom-blocks. Import React hooks from @notionhq/custom-blocks/react. Getters throw before initialization completes. In React, call context hooks inside NotionCustomBlock, which waits for initialization before rendering its children. Subscriptions can register before initialization. They wait for initialization before delivering the initial value, or deliver immediately if initialization is complete. Start initialization with initCustomBlock() or NotionCustomBlock. Subscriptions do not start it themselves. These initialization APIs also report failures. Each subscription returns an unsubscribe function. Repeated cleanup calls have no effect. After initial delivery, subscriptions compare values with Object.is. Objects use referential equality: a new reference triggers a callback even if its contents are unchanged. Updates to other context values do not trigger the callback. React hooks follow the same comparison rules.

Getter

Read the current theme after initialization:

Subscription

Register before initialization to receive the initial theme and later changes:

React hook

Use useTheme() inside NotionCustomBlock to keep the component current. React handles subscription cleanup when the component unmounts.

Current user

Use getCurrentUser(), subscribeToCurrentUser(), and useCurrentUser() to access the viewing user’s NotionUser. See users for profile fields and user APIs.

Custom block ID

Use getBlockId(), subscribeToBlockId(), and useBlockId() to access the custom block’s own NotionBlockId. The ID is stable for the lifetime of the block. Each subscription delivers once, unless cancelled before initialization. You can register before initialization without an error.

Parent

Use getParent(), subscribeToParent(), and useParent() to access the block’s NotionParent. For most blocks, the parent is the immediate container in the document tree. It is the containing page only when the block sits directly inside that page. Custom views are an exception. Their backing custom block is attached to a view. The bridge reports the data source associated with that view as { type: "data_source_id", data_source_id }. For a custom block directly inside a page surface, the bridge reports { type: "page_id", page_id }.

Containing page

Use getPage(), subscribeToPage(), and usePage() to access a CustomBlockPage with the page’s id and parent. The containing page is the nearest page surface. Its parent describes the page surface, not the custom block. A page surface can be a regular page, a full-page database, or a wiki root.

Parent values

useParent() and usePage().parent use the NotionParent type. The result has one of these shapes: A wiki root is a page surface. The bridge treats it as a page surface for page context, parent reporting, and page APIs:
  • usePage().id can be the wiki root’s ID.
  • A custom block directly on the wiki root can receive that ID as useParent().page_id.
  • usePage().parent describes the wiki root’s own parent.

Theme and contrast mode

The theme APIs return "light" or "dark". The contrast mode APIs return "standard" or "high". See appearance and sizing for styles and examples.

Manifest

Use getManifest(), subscribeToManifest(), and useManifest() to access the declared CustomBlockManifest. The manifest stays fixed for the lifetime of the running block, so each subscription delivers it once. You can register before initialization without an error. See data sources for manifest details and subscribeToDataSource() for query snapshots.