Repository: GitbookIO/gitbook
Pull request #3233: Dynamic TOC height
Author: login: zenoachtig
Created: 2025-05-13T18:27:31Z | Merged: 2025-05-20T12:13:58Z

This PR adds a client-side available height calculation for the TableOfContents component. This solves two issues:
- When the announcement banner is enabled, the TOC's static height is too high to fit in the screen initially. When scrolling down the banner disappears out of frame, which means the TOC needs to grow to take the available height (causing issues like RND-7090)
- When reaching the footer, the TOC bumps up against it and moves visually up the screen, with its top part cut off. We should subtract the footer's visible height from the TOC height.

Important to note: to prevent layout shift the TOC still has a number of `top-*` and `h-*` classes added to it, to set its initial positioning as close as possible on the server. Once the client loads we override these classes with the dynamic height through CSS variables.

# Before
https://github.com/user-attachments/assets/eed57279-331a-4b33-a56a-1315b432ce2f

# After
https://github.com/user-attachments/assets/9c2b0a7a-95cd-4bda-91ff-d41d661b1b9e

Fixes RND-7090


Diff:
diff --git a/.changeset/slow-lizards-obey.md b/.changeset/slow-lizards-obey.md
new file mode 100644
index 0000000000..ce1ef0e04c
--- /dev/null
+++ b/.changeset/slow-lizards-obey.md
@@ -0,0 +1,5 @@
+---
+"gitbook": patch
+---
+
+Make TOC height dynamic based on visible header and footer elements
diff --git a/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx b/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx
index c89bb24804..522bde0ca3 100644
--- a/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx
+++ b/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx
@@ -25,7 +25,7 @@ export function AnnouncementBanner(props: {
     const style = BANNER_STYLES[announcement.style];
 
     return (
-        <div className="announcement-banner theme-bold:bg-header-background pt-4 pb-2">
+        <div id="announcement-banner" className="theme-bold:bg-header-background pt-4 pb-2">
             <div className="scroll-nojump">
                 <div className={tcls('relative', CONTAINER_STYLE)}>
                     <Tag
diff --git a/packages/gitbook/src/components/Footer/Footer.tsx b/packages/gitbook/src/components/Footer/Footer.tsx
index 776c0a4af4..5723d67f3c 100644
--- a/packages/gitbook/src/components/Footer/Footer.tsx
+++ b/packages/gitbook/src/components/Footer/Footer.tsx
@@ -25,6 +25,7 @@ export function Footer(props: { context: GitBookSiteContext }) {
 
     return (
         <footer
+            id="site-footer"
             className={tcls(
                 'border-tint-subtle border-t',
                 // If the footer only contains a mode toggle, we only show it on smaller screens
diff --git a/packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx b/packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx
index c7d2f35b6e..c6f141425a 100644
--- a/packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx
+++ b/packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx
@@ -75,7 +75,7 @@ export async function CustomizationRootLayout(props: {
             lang={customization.internationalization.locale}
             className={tcls(
                 customization.header.preset === CustomizationHeaderPreset.None
-                    ? 'site-header-none'
+                    ? null
                     : 'scroll-pt-[76px]', // Take the sticky header in consideration for the scrolling
                 customization.styling.corners === CustomizationCorners.Straight
                     ? ' straight-corners'
diff --git a/packages/gitbook/src/components/RootLayout/globals.css b/packages/gitbook/src/components/RootLayout/globals.css
index 71dae7cc6b..15c09614e3 100644
--- a/packages/gitbook/src/components/RootLayout/globals.css
+++ b/packages/gitbook/src/components/RootLayout/globals.css
@@ -161,6 +161,6 @@ html.dark {
     color-scheme: dark light;
 }
 
-html.announcement-hidden .announcement-banner {
+html.announcement-hidden #announcement-banner {
     @apply hidden;
 }
diff --git a/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx b/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx
index dcfb287660..7a6993fde1 100644
--- a/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx
+++ b/packages/gitbook/src/components/TableOfContents/TableOfContents.tsx
@@ -6,6 +6,7 @@ import { tcls } from '@/lib/tailwind';
 
 import { PagesList } from './PagesList';
 import { TOCScrollContainer } from './TOCScroller';
+import { TableOfContentsScript } from './TableOfContentsScript';
 import { Trademark } from './Trademark';
 
 export function TableOfContents(props: {
@@ -17,97 +18,107 @@ export function TableOfContents(props: {
     const { space, customization, pages } = context;
 
     return (
-        <aside // Sidebar container, responsible for setting the right dimensions and position for the sidebar.
-            data-testid="table-of-contents"
-            className={tcls(
-                'group',
-                'text-sm',
+        <>
+            <aside // Sidebar container, responsible for setting the right dimensions and position for the sidebar.
+                data-testid="table-of-contents"
+                id="table-of-contents"
+                className={tcls(
+                    'group',
+                    'text-sm',
 
-                'grow-0',
-                'shrink-0',
-                'basis-full',
-                'lg:basis-72',
-                'page-no-toc:lg:basis-56',
+                    'grow-0',
+                    'shrink-0',
+                    'basis-full',
+                    'lg:basis-72',
+                    'page-no-toc:lg:basis-56',
 
-                'relative',
-                'z-[1]',
-                'lg:sticky',
-                // Without header
-                'lg:top-0',
-                'lg:h-screen',
+                    'relative',
+                    'z-[1]',
+                    'lg:sticky',
 
-                // With header
-                'site-header:lg:top-16',
-                'site-header:lg:h-[calc(100vh_-_4rem)]',
+                    // Server-side static positioning
+                    'lg:top-0',
+                    'lg:h-screen',
+                    'announcement:lg:h-[calc(100vh-4.25rem)]',
 
-                // With header and sections
-                'site-header-sections:lg:top-[6.75rem]',
-                'site-header-sections:lg:h-[calc(100vh_-_6.75rem)]',
+                    'site-header:lg:top-16',
+                    'site-header:lg:h-[calc(100vh-4rem)]',
+                    'announcement:site-header:lg:h-[calc(100vh-4rem-4.25rem)]',
 
-                'pt-6',
-                'pb-4',
-                'sidebar-filled:lg:pr-6',
-                'page-no-toc:lg:pr-0',
+                    'site-header-sections:lg:top-[6.75rem]',
+                    'site-header-sections:lg:h-[calc(100vh-6.75rem)]',
+                    'announcement:site-header-sections:lg:h-[calc(100vh-6.75rem-4.25rem)]',
 
-                'hidden',
-                'navigation-open:!flex',
-                'lg:flex',
-                'page-no-toc:lg:hidden',
-                'page-no-toc:xl:flex',
-                'site-header-none:page-no-toc:lg:flex',
-                'flex-col',
-                'gap-4',
+                    // Client-side dynamic positioning (CSS vars applied by script)
+                    '[html[style*="--toc-top-offset"]_&]:lg:!top-[var(--toc-top-offset)]',
+                    '[html[style*="--toc-height"]_&]:lg:!h-[var(--toc-height)]',
 
-                'navigation-open:border-b',
-                'border-tint-subtle'
-            )}
-        >
-            {header && header}
-            <div // The actual sidebar, either shown with a filled bg or transparent.
-                className={tcls(
-                    'lg:-ms-5',
-                    'relative flex flex-grow flex-col overflow-hidden border-tint-subtle',
+                    'pt-6',
+                    'pb-4',
+                    'sidebar-filled:lg:pr-6',
+                    'page-no-toc:lg:pr-0',
 
-                    'sidebar-filled:bg-tint-subtle',
-                    'theme-muted:bg-tint-subtle',
-                    '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
-                    '[html.sidebar-filled.theme-muted_&]:bg-tint-base',
-                    '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base',
-                    '[html.sidebar-filled.theme-gradient_&]:border',
-                    'page-no-toc:!bg-transparent',
+                    'hidden',
+                    'navigation-open:!flex',
+                    'lg:flex',
+                    'page-no-toc:lg:hidden',
+                    'page-no-toc:xl:flex',
+                    'site-header-none:page-no-toc:lg:flex',
+                    'flex-col',
+                    'gap-4',
 
-                    'sidebar-filled:rounded-xl',
-                    'straight-corners:rounded-none'
+                    'navigation-open:border-b',
+                    'border-tint-subtle'
                 )}
             >
-                {innerHeader && <div className="px-5 *:my-4">{innerHeader}</div>}
-                <TOCScrollContainer // The scrollview inside the sidebar
+                {header && header}
+                <div // The actual sidebar, either shown with a filled bg or transparent.
                     className={tcls(
-                        'flex flex-grow flex-col p-2',
-                        customization.trademark.enabled && 'lg:pb-20',
-                        'lg:gutter-stable overflow-y-auto',
-                        '[&::-webkit-scrollbar]:bg-transparent',
-                        '[&::-webkit-scrollbar-thumb]:bg-transparent',
-                        'group-hover:[&::-webkit-scrollbar]:bg-tint-subtle',
-                        'group-hover:[&::-webkit-scrollbar-thumb]:bg-tint-7',
-                        'group-hover:[&::-webkit-scrollbar-thumb:hover]:bg-tint-8'
+                        'lg:-ms-5',
+                        'relative flex flex-grow flex-col overflow-hidden border-tint-subtle',
+
+                        'sidebar-filled:bg-tint-subtle',
+                        'theme-muted:bg-tint-subtle',
+                        '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
+                        '[html.sidebar-filled.theme-muted_&]:bg-tint-base',
+                        '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base',
+                        '[html.sidebar-filled.theme-gradient_&]:border',
+                        'page-no-toc:!bg-transparent',
+
+                        'sidebar-filled:rounded-xl',
+                        'straight-corners:rounded-none'
                     )}
                 >
-                    <PagesList
-                        rootPages={pages}
-                        pages={pages}
-                        context={context}
-                        style="page-no-toc:hidden border-tint-subtle sidebar-list-line:border-l"
-                    />
-                    {customization.trademark.enabled ? (
-                        <Trademark
-                            space={space}
-                            customization={customization}
-                            placement={SiteInsightsTrademarkPlacement.Sidebar}
+                    {innerHeader && <div className="px-5 *:my-4">{innerHeader}</div>}
+                    <TOCScrollContainer // The scrollview inside the sidebar
+                        className={tcls(
+                            'flex flex-grow flex-col p-2',
+                            customization.trademark.enabled && 'lg:pb-20',
+                            'lg:gutter-stable overflow-y-auto',
+                            '[&::-webkit-scrollbar]:bg-transparent',
+                            '[&::-webkit-scrollbar-thumb]:bg-transparent',
+                            'group-hover:[&::-webkit-scrollbar]:bg-tint-subtle',
+                            'group-hover:[&::-webkit-scrollbar-thumb]:bg-tint-7',
+                            'group-hover:[&::-webkit-scrollbar-thumb:hover]:bg-tint-8'
+                        )}
+                    >
+                        <PagesList
+                            rootPages={pages}
+                            pages={pages}
+                            context={context}
+                            style="page-no-toc:hidden border-tint-subtle sidebar-list-line:border-l"
                         />
-                    ) : null}
-                </TOCScrollContainer>
-            </div>
-        </aside>
+                        {customization.trademark.enabled ? (
+                            <Trademark
+                                space={space}
+                                customization={customization}
+                                placement={SiteInsightsTrademarkPlacement.Sidebar}
+                            />
+                        ) : null}
+                    </TOCScrollContainer>
+                </div>
+            </aside>
+            <TableOfContentsScript />
+        </>
     );
 }
diff --git a/packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx b/packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx
new file mode 100644
index 0000000000..a4e6bea18c
--- /dev/null
+++ b/packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx
@@ -0,0 +1,73 @@
+'use client';
+
+import { useEffect } from 'react';
+
+/**
+ * Adjusts TableOfContents height based on visible elements
+ */
+export function TableOfContentsScript() {
+    useEffect(() => {
+        const root = document.documentElement;
+
+        // Calculate and set TOC dimensions
+        const updateTocLayout = () => {
+            // Get key elements
+            const header = document.getElementById('site-header');
+            const banner = document.getElementById('announcement-banner');
+            const footer = document.getElementById('site-footer');
+
+            // Set sticky top position based on header
+            const headerHeight = header?.offsetHeight ?? 0;
+            root.style.setProperty('--toc-top-offset', `${headerHeight}px`);
+
+            // Start with full viewport height minus header
+            let height = window.innerHeight - headerHeight;
+
+            // Subtract visible banner (if any)
+            if (banner && window.getComputedStyle(banner).display !== 'none') {
+                const bannerRect = banner.getBoundingClientRect();
+                if (bannerRect.height > 0 && bannerRect.bottom > 0) {
+                    height -= Math.min(bannerRect.height, bannerRect.bottom);
+                }
+            }
+
+            // Subtract visible footer (if any)
+            if (footer) {
+                const footerRect = footer.getBoundingClientRect();
+                if (footerRect.top < window.innerHeight) {
+                    height -= Math.min(footerRect.height, window.innerHeight - footerRect.top);
+                }
+            }
+
+            // Update height
+            root.style.setProperty('--toc-height', `${height}px`);
+        };
+
+        // Initial update
+        updateTocLayout();
+
+        // Let the browser handle scroll throttling naturally
+        window.addEventListener('scroll', updateTocLayout, { passive: true });
+        window.addEventListener('resize', updateTocLayout, { passive: true });
+
+        // Use MutationObserver for DOM changes
+        const observer = new MutationObserver(() => {
+            requestAnimationFrame(updateTocLayout);
+        });
+
+        // Only observe what matters
+        observer.observe(document.documentElement, {
+            subtree: true,
+            attributes: true,
+            attributeFilter: ['style', 'class'],
+        });
+
+        return () => {
+            observer.disconnect();
+            window.removeEventListener('scroll', updateTocLayout);
+            window.removeEventListener('resize', updateTocLayout);
+        };
+    }, []);
+
+    return null;
+}
diff --git a/packages/gitbook/src/components/TableOfContents/index.ts b/packages/gitbook/src/components/TableOfContents/index.ts
index 715a3a239e..6eeff92697 100644
--- a/packages/gitbook/src/components/TableOfContents/index.ts
+++ b/packages/gitbook/src/components/TableOfContents/index.ts
@@ -1 +1,4 @@
-export * from './TableOfContents';
+export { TableOfContents } from './TableOfContents';
+export { PagesList } from './PagesList';
+export { TOCScrollContainer } from './TOCScroller';
+export { Trademark } from './Trademark';
diff --git a/packages/gitbook/tailwind.config.ts b/packages/gitbook/tailwind.config.ts
index 2e5b7c359f..9d248c9a40 100644
--- a/packages/gitbook/tailwind.config.ts
+++ b/packages/gitbook/tailwind.config.ts
@@ -458,12 +458,16 @@ const config: Config = {
             /**
              * Variant when a header is displayed.
              */
-            addVariant('site-header-none', 'html.site-header-none &');
+            addVariant('site-header-none', 'body:not(:has(#site-header:not(.mobile-only))) &');
             addVariant('site-header', 'body:has(#site-header:not(.mobile-only)) &');
             addVariant('site-header-sections', [
                 'body:has(#site-header:not(.mobile-only) #sections) &',
                 'body:has(.page-no-toc):has(#site-header:not(.mobile-only) #variants) &',
             ]);
+            addVariant(
+                'announcement',
+                'html:not(.announcement-hidden):has(#announcement-banner) &'
+            );
 
             const customisationVariants = {
                 // Sidebar styles


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR refines the styling and behavior of the TableOfContents by accounting for the announcement banner height and other header variations. Key changes include:
- Updating Tailwind configuration variants to accommodate new header and announcement states.
- Introducing a client-side script (TableOfContentsScript) for dynamic TOC positioning.
- Migrating from the legacy TableOfContents export to a more adaptive component (AdaptiveTableOfContents) and updating related layout and styling.

### Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                                                             | Description                                                         |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| packages/gitbook/tailwind.config.ts                                              | Updated variant selectors to improve header and announcement styling. |
| packages/gitbook/src/components/TableOfContents/index.ts                         | Refactored exports to include AdaptiveTableOfContents and additional modules. |
| packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx          | Added a new client-side script for dynamic TOC size and position adjustments. |
| packages/gitbook/src/components/TableOfContents/TableOfContents.tsx                | Adjusted class names and included new dynamic positioning and announcement variants. |
| packages/gitbook/src/components/TableOfContents/AdaptiveTableOfContents.tsx        | Created a wrapper for combining server-rendered TOC with dynamic behavior. |
| packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx                      | Replaced TableOfContents with AdaptiveTableOfContents for enhanced functionality. |
| packages/gitbook/src/components/RootLayout/globals.css                           | Updated CSS selector for announcement banner to use an ID instead of a class. |
| packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx           | Modified header class handling to use an array-based syntax for conditional classes. |
| packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx              | Assigned an ID to the banner element, ensuring consistency with the new selectors. |
</details>



<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx:79**
* Ensure that the tcls class concatenation helper correctly handles arrays of classes; if not, convert the array to a space-delimited string before passing it to avoid unexpected behavior.
```
: ['site-header', 'scroll-pt-[76px]'], // Take the sticky header in consideration for the scrolling
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T18:28:02Z
user: login: conico974
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T10:04:54Z
user: login: zenoachtig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T10:48:50Z
user: login: conico974
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T12:00:11Z
user: login: conico974
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T12:13:10Z

Review comments:
diff_hunk: @@ -0,0 +1,73 @@
+'use client';
+
+import { useEffect } from 'react';
+
+/**
+ * Adjusts TableOfContents height based on visible elements
+ */
+export function TableOfContentsScript() {
+    useEffect(() => {
+        const root = document.documentElement;
+
+        // Calculate and set TOC dimensions
+        const updateTocLayout = () => {
+            // Get key elements
+            const header = document.getElementById('site-header');
+            const banner = document.getElementById('announcement-banner');
+            const footer = document.getElementById('site-footer');
+
+            // Set sticky top position based on header
+            const headerHeight = header?.offsetHeight ?? 0;
+            root.style.setProperty('--toc-top-offset', `${headerHeight}px`);
+
+            // Start with full viewport height minus header
+            let height = window.innerHeight - headerHeight;
+
+            // Subtract visible banner (if any)
+            if (banner && banner?.computedStyleMap().get('display') !== 'none') {
path: packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx
user: login: conico974
body: `computedStyleMap` doesn't work on Firefox https://developer.mozilla.org/en-US/docs/Web/API/Element/computedStyleMap
created_at: 2025-05-20T10:04:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+'use client';
+
+import { useEffect } from 'react';
+
+/**
+ * Adjusts TableOfContents height based on visible elements
+ */
+export function TableOfContentsScript() {
+    useEffect(() => {
+        const root = document.documentElement;
+
+        // Calculate and set TOC dimensions
+        const updateTocLayout = () => {
+            // Get key elements
+            const header = document.getElementById('site-header');
+            const banner = document.getElementById('announcement-banner');
+            const footer = document.getElementById('site-footer');
+
+            // Set sticky top position based on header
+            const headerHeight = header?.offsetHeight ?? 0;
+            root.style.setProperty('--toc-top-offset', `${headerHeight}px`);
+
+            // Start with full viewport height minus header
+            let height = window.innerHeight - headerHeight;
+
+            // Subtract visible banner (if any)
+            if (banner && banner?.computedStyleMap().get('display') !== 'none') {
path: packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx
user: login: zenoachtig
body: Had no idea, thank you! Changed in favour of the classic `window.getComputedStyle()`
created_at: 2025-05-20T10:48:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+'use client';
+
+import { useEffect } from 'react';
+
+/**
+ * Adjusts TableOfContents height based on visible elements
+ */
+export function TableOfContentsScript() {
+    useEffect(() => {
+        const root = document.documentElement;
+
+        // Calculate and set TOC dimensions
+        const updateTocLayout = () => {
+            // Get key elements
+            const header = document.getElementById('site-header');
+            const banner = document.getElementById('announcement-banner');
+            const footer = document.getElementById('site-footer');
+
+            // Set sticky top position based on header
+            const headerHeight = header?.offsetHeight ?? 0;
+            root.style.setProperty('--toc-top-offset', `${headerHeight}px`);
+
+            // Start with full viewport height minus header
+            let height = window.innerHeight - headerHeight;
+
+            // Subtract visible banner (if any)
+            if (banner && banner?.computedStyleMap().get('display') !== 'none') {
path: packages/gitbook/src/components/TableOfContents/TableOfContentsScript.tsx
user: login: conico974
body: Me neither to be honest :smile: , i just tested on Firefox and it crashed right away
created_at: 2025-05-20T12:00:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-13T18:27:34Z
body: ###  🦋  Changeset detected

Latest commit: b851dad786c429fdcb4b55d848ac227bda411431

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name    | Type  |
| ------- | ----- |
| gitbook | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/GitbookIO/gitbook/new/announcement-banner-toc-height?filename=.changeset/two-scissors-think.md&value=---%0A%22gitbook%22%3A%20patch%0A---%0A%0ADynamic%20TOC%20height%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-13T18:31:50Z
body: Summary of the deployments:

### Version 1

| Version | URL | Status |
| --- | --- | --- |
| Latest commit | [https://310be5d4.gitbook-open.pages.dev](https://310be5d4.gitbook-open.pages.dev) | ✅ |
| PR | [https://pr3233.gitbook-open.pages.dev](https://pr3233.gitbook-open.pages.dev) | ✅ |

### Version 2

| Version | URL | Status |
| --- | --- | --- |
| Vercel | [https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app](https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app) | ✅ |
| Cloudflare | [https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev](https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev) | ✅ |

### Test content

| Site | `v1` | `2v` | `2c` |
| --- | --- | --- | --- |
| GitBook | [https://310be5d4.gitbook-open.pages.dev/gitbook.com/docs](https://310be5d4.gitbook-open.pages.dev/gitbook.com/docs) | [https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app/url/gitbook.com/docs](https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app/url/gitbook.com/docs) | [https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev/url/gitbook.com/docs](https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev/url/gitbook.com/docs) |
| E2E | [https://310be5d4.gitbook-open.pages.dev/gitbook.gitbook.io/test-gitbook-open](https://310be5d4.gitbook-open.pages.dev/gitbook.gitbook.io/test-gitbook-open) | [https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app/url/gitbook.gitbook.io/test-gitbook-open](https://gitbook-v2-bvf7aoaw5-gitbook.vercel.app/url/gitbook.gitbook.io/test-gitbook-open) | [https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev/url/gitbook.gitbook.io/test-gitbook-open](https://2559163f-gitbook-open-v2-preview.gitbook.workers.dev/url/gitbook.gitbook.io/test-gitbook-open) |
author_association: CONTRIBUTOR
user: login: argos-ci[bot]
created_at: 2025-05-13T18:34:20Z
body: **The latest updates on your projects.** Learn more about [Argos notifications ↗︎](https://argos-ci.com/docs/notifications)

| Build | Status | Details | Updated (UTC) |
| :---- | :----- | :------ | :------------ |
| **customers-v1** ([Inspect](https://app.argos-ci.com/GitbookIO/gitbook/builds/8193)) | 👍 Changes approved | 2 changed | May 20, 2025, 10:54 AM |
| **customers-v2** ([Inspect](https://app.argos-ci.com/GitbookIO/gitbook/builds/8195)) | 👍 Changes approved | 81 changed | May 20, 2025, 10:56 AM |
| **default** ([Inspect](https://app.argos-ci.com/GitbookIO/gitbook/builds/8196)) | 👍 Changes approved | 8 changed | May 20, 2025, 10:56 AM |
| **v2-cloudflare** ([Inspect](https://app.argos-ci.com/GitbookIO/gitbook/builds/8197)) | 👍 Changes approved | 4 changed | May 20, 2025, 10:58 AM |
| **v2-vercel** ([Inspect](https://app.argos-ci.com/GitbookIO/gitbook/builds/8198)) | 👍 Changes approved | 4 changed | May 20, 2025, 10:59 AM |
author_association: NONE
user: login: linear[bot]
created_at: 2025-05-14T15:43:57Z
body: <p><a href="https://linear.app/gitbook-x/issue/RND-7090/make-watermark-sticky-to-fix-site-shift-due-to-banner">RND-7090 Make watermark sticky to fix site shift due to banner</a></p>
author_association: NONE