diff --git a/.changeset/long-wombats-raise.md b/.changeset/long-wombats-raise.md
new file mode 100644
index 0000000000..dc6c8725d0
--- /dev/null
+++ b/.changeset/long-wombats-raise.md
@@ -0,0 +1,5 @@
+---
+"gitbook": patch
+---
+
+Add icon support in tab items
diff --git a/bun.lock b/bun.lock
index cfde53b26a..c5756be0f6 100644
--- a/bun.lock
+++ b/bun.lock
@@ -359,7 +359,7 @@
"react-dom": "catalog:",
},
"catalog": {
- "@gitbook/api": "0.181.0",
+ "@gitbook/api": "0.182.0",
"@scalar/api-client-react": "^1.3.46",
"@tsconfig/node20": "^20.1.6",
"@tsconfig/strictest": "^2.0.6",
@@ -755,7 +755,7 @@
"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@7.2.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.2.0" } }, "sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q=="],
- "@gitbook/api": ["@gitbook/api@0.181.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-tj7bPzty9jlG3zKiZlmvvqalbTCtukmU/BlFB3HPRZM4jQrmLBc+Ya0rOyTpTaLJEH1BZy0U9HGsoCfbP5W8Fg=="],
+ "@gitbook/api": ["@gitbook/api@0.182.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-O5CgVzbRL2esrsQJ816UcHMqY22fsMFAeLRQ8Gapus4S+/teXk3nf5YU5T10o3112niSD3QeNp2uIcsyMGOweg=="],
"@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"],
diff --git a/package.json b/package.json
index 4cd67423ee..b5d4373667 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"catalog": {
"@tsconfig/strictest": "^2.0.6",
"@tsconfig/node20": "^20.1.6",
- "@gitbook/api": "0.181.0",
+ "@gitbook/api": "0.182.0",
"@scalar/api-client-react": "^1.3.46",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
diff --git a/packages/gitbook/src/components/DocumentView/Tabs/DynamicTabs.tsx b/packages/gitbook/src/components/DocumentView/Tabs/DynamicTabs.tsx
index c5a7a07a7c..6ba79f9510 100644
--- a/packages/gitbook/src/components/DocumentView/Tabs/DynamicTabs.tsx
+++ b/packages/gitbook/src/components/DocumentView/Tabs/DynamicTabs.tsx
@@ -15,7 +15,7 @@ import { useLanguage } from '@/intl/client';
import { tString } from '@/intl/translate';
import { getLocalStorageItem, setLocalStorageItem } from '@/lib/browser';
import { tcls } from '@/lib/tailwind';
-import { Icon } from '@gitbook/icons';
+import { Icon, type IconName } from '@gitbook/icons';
import { useRouter } from 'next/navigation';
interface TabsState {
@@ -56,6 +56,7 @@ const TITLES_MAX = 5;
export interface TabsItem {
id: string;
title: string;
+ icon?: IconName;
body: React.ReactNode;
}
@@ -319,6 +320,7 @@ function TabsDropdownMenu(props: {
key={tab.id}
onClick={() => onSelect(tab.id)}
active={tab.id === activeTabId}
+ leadingIcon={tab.icon}
>
{tab.title}
@@ -347,7 +349,8 @@ const TabItem = memo(function TabItem(props: {
id={getTabButtonId(tab.id)}
onClick={() => onSelect(tab.id)}
>
- {tab.title}
+ {tab.icon && }
+ {tab.title}
);
});
@@ -411,7 +414,7 @@ function TabButton(
{...rest}
type="button"
className={tcls(
- 'relative inline-block max-w-full truncate px-3.5 py-2 font-medium text-sm transition-[color]',
+ 'relative inline-flex max-w-full items-center gap-1.5 px-3.5 py-2 font-medium text-sm transition-[color]',
props.className
)}
/>
diff --git a/packages/gitbook/src/components/DocumentView/Tabs/Tabs.tsx b/packages/gitbook/src/components/DocumentView/Tabs/Tabs.tsx
index a7b85e23be..4151d0e9e8 100644
--- a/packages/gitbook/src/components/DocumentView/Tabs/Tabs.tsx
+++ b/packages/gitbook/src/components/DocumentView/Tabs/Tabs.tsx
@@ -1,4 +1,6 @@
import type { DocumentBlockTabs } from '@gitbook/api';
+import type { IconName } from '@gitbook/icons';
+import { validateIconName } from '@gitbook/icons/icons';
import { tcls } from '@/lib/tailwind';
@@ -20,9 +22,13 @@ export function Tabs(props: BlockProps) {
throw new Error('Tab block is missing a key');
}
+ const icon: IconName | undefined =
+ tab.data.icon && validateIconName(tab.data.icon) ? tab.data.icon : undefined;
+
return {
id: tab.meta?.id ?? tab.key,
title: tab.data.title ?? '',
+ icon,
body: (
0;
- // @ts-expect-error available in next API update
const pageActionsEnabled = page.layout.actions !== false;
// Show page actions if *any* of the actions are enabled
diff --git a/packages/gitbook/src/lib/icons/inline.ts b/packages/gitbook/src/lib/icons/inline.ts
index d8d000cddd..76e3d01144 100644
--- a/packages/gitbook/src/lib/icons/inline.ts
+++ b/packages/gitbook/src/lib/icons/inline.ts
@@ -358,7 +358,7 @@ function collectDocumentIconSourceRequests(
const record = node as Record;
- if (record.type === 'icon' || record.type === 'button') {
+ if (record.type === 'icon' || record.type === 'button' || record.type === 'tabs-item') {
const data = record.data;
if (data && typeof data === 'object') {
addIconSourceRequest(requests, (data as Record).icon, iconStyle);
diff --git a/packages/gitbook/src/lib/pages.test.ts b/packages/gitbook/src/lib/pages.test.ts
index 114d396585..e1be6faeeb 100644
--- a/packages/gitbook/src/lib/pages.test.ts
+++ b/packages/gitbook/src/lib/pages.test.ts
@@ -85,6 +85,7 @@ describe('resolveFirstDocument', () => {
width: RevisionPageLayoutOptionsWidth.Default,
metadata: true,
tags: true,
+ actions: true,
},
},
],
@@ -137,6 +138,7 @@ describe('resolveFirstDocument', () => {
width: RevisionPageLayoutOptionsWidth.Default,
metadata: true,
tags: true,
+ actions: true,
},
},
];
@@ -182,6 +184,7 @@ describe('resolvePagePath', () => {
width: RevisionPageLayoutOptionsWidth.Default,
metadata: true,
tags: true,
+ actions: true,
},
},
];
@@ -257,6 +260,7 @@ describe('resolvePagePath', () => {
width: RevisionPageLayoutOptionsWidth.Default,
metadata: true,
tags: true,
+ actions: true,
},
},
],
@@ -374,6 +378,7 @@ function createDocumentPage(id: string, path: string, hidden = false): RevisionP
width: RevisionPageLayoutOptionsWidth.Default,
metadata: true,
tags: true,
+ actions: true,
},
};
}