Skip to main content
Add a record tab by creating an extension folder under src/app/extensions/ whose extension.tsx default-exports a defineExtension call with type: "record-tab". See App structure for the discovery rules. Use it for content that doesn’t fit a widget: tables, timelines, a dashboard about the record. For UI that isn’t about one record, use a page.
Unlike widgets, record tabs don’t need to be added by hand. Once a workspace installs your app, the tab appears on every record page it targets, after Attio’s own tabs.

Example

The tab component itself can live in a sibling file inside the extension folder:
src/app/extensions/enrichment/extension.tsx
src/app/extensions/enrichment/enrichment-tab.tsx

Arguments

"record-tab"
required
Identifies this extension as a record tab.
string
required
The unique identifier for this tab. It is the last segment of the tab’s URL and the value you pass as tab when navigating to it. Never shown to the user.It must not be the slug of a built-in tab. Using one fails the build with RECORD_TAB_ID_IS_NATIVE_TAB_SLUG. The reserved slugs are overview, activity, calls, notes, tasks, emails, files, team, company, companies, associated_people and associated_users.
string
required
The label shown in the record page tab bar.
(props: { recordId: string, object: ObjectSlug }) => React.JSX.Element
required
A React component that renders the contents of the tab.It can suspend while loading data. Return an EmptyState as the only child when there is nothing to show yet.
ObjectSlug | Array<ObjectSlug>
A single slug or an array of slugs selecting which objects the tab appears on.Defaults to undefined, which shows the tab on all objects.The built-in slugs are

Where the tab appears

After install, the tab shows on every record page matching objects, placed after Attio’s built-in tabs. Workspace admins can remove it, add it back and reorder it through “Configure page” on the record page, the same editor they use for the built-in tabs. You don’t need to document any of that for your users: it works like every other tab. Every record tab has a stable URL:
Loading that URL cold lands directly on your tab. To build one from inside your app, use Destinations.record with the tab option rather than assembling the path yourself.

Lifecycle

Tabs follow your app’s versions. Publishing a version that no longer defines a tab removes it from every workspace on update, including any position an admin gave it. If a later version brings the tab back, it is created fresh at the end of the tab bar. Placement is not preserved across removal, so don’t ship a version without a tab you intend to keep.