# React Integration

This guide shows how to integrate the Probo cookie banner into a React application, build a `useConsent` hook for consent-aware rendering, and handle Next.js-specific requirements.

## Installation

```bash
npm install @probo/cookie-banner
```

## Rendering the Themed Banner

The themed banner is a Web Component. Register it once and place the custom element in your layout.

  

```tsx
// src/components/CookieBanner.tsx

let registered = false;

export function CookieBanner() {
  useEffect(() => {
    if (!registered) {
      registerCookieBanner();
      registered = true;
    }
  }, []);

  return (
    <probo-cookie-banner
      banner-id="YOUR_BANNER_ID"
      base-url="https://your-probo-instance.com/api/cookie-banner/v1/"
      position="bottom-left"
    />
  );
}
```

  

  

Render `` once at the root of your application, and place `<probo-settings-link>` in your header or footer so visitors can reopen preferences:

```tsx
// src/App.tsx

export default function App() {
  return (
    <>
      
      
      <footer>
        <probo-settings-link>Cookie settings</probo-settings-link>
      </footer>
    </>
  );
}
```

  

The banner handles everything from there — it fetches the configuration, shows the consent dialog when needed, and records consent. In opt-out jurisdictions the dialog never opens on its own and the settings link is the visitor's only route to their choices; under CCPA that link shows “Your Privacy Choices” with the official opt-out icon and opens the Privacy Choices panel.

### TypeScript

If TypeScript complains about the `<probo-cookie-banner>` JSX element, add a type declaration:

```ts
// src/probo.d.ts
declare namespace JSX {
  interface IntrinsicElements {
    "probo-cookie-banner": React.DetailedHTMLProps<
      React.HTMLAttributes & {
        "banner-id": string;
        "base-url": string;
        position?:
          | "bottom-left"
          | "bottom-right"
          | "bottom-center"
          | "top-left"
          | "top-right"
          | "top-center";
        lang?: string;
      },
      HTMLElement
    >;
    "probo-settings-link": React.DetailedHTMLProps<
      React.HTMLAttributes,
      HTMLElement
    >;
    "probo-acknowledge-button": React.DetailedHTMLProps<
      React.HTMLAttributes,
      HTMLElement
    >;
    "probo-privacy-choices": React.DetailedHTMLProps<
      React.HTMLAttributes,
      HTMLElement
    >;
  }
}
```

## The `useConsent` Hook

Use the [Consent Manager API](/docs/product/cookie-banner/consent-manager) to build a React hook that gives components reactive access to consent state.

```tsx
// src/hooks/useConsent.ts

const consent = getConsent();

function subscribe(onStoreChange: () => void): () => void {
  return consent.subscribe(onStoreChange);
}

function getSnapshot(): Record<string, boolean> {
  return consent.getAll();
}

function getServerSnapshot(): Record<string, boolean> {
  return {};
}

export function useConsent(): Record<string, boolean> {
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}
```

This hook re-renders the component whenever consent state changes — on initial resolution and after the visitor updates their preferences.

### Usage

```tsx

export function AnalyticsLoader() {
  const consent = useConsent();

  if (!consent.analytics) {
    return null;
  }

  return ;
}
```

### Checking a single category

```tsx

export function ChatWidget() {
  const consent = useConsent();

  if (!consent.functional) {
    return <p>Enable functional cookies to use live chat.</p>;
  }

  return ;
}
```

## Imperative Consent Checks

For code that runs outside of React's render cycle — event handlers, side effects, or non-React modules — use `getConsent()` directly instead of the hook:

```ts

export function trackEvent(name: string) {
  if (getConsent().has("analytics")) {
    analytics.track(name);
  }
}
```

See the [Consent Manager API](/docs/product/cookie-banner/consent-manager) reference for the full API.

## Next.js

The cookie banner SDK accesses `document`, `window`, and `localStorage`, so it must run on the client. In the Next.js App Router, mark the component with `"use client"`:

```tsx
// src/components/CookieBanner.tsx
"use client";

let registered = false;

export function CookieBanner() {
  useEffect(() => {
    if (!registered) {
      registerCookieBanner();
      registered = true;
    }
  }, []);

  return (
    <probo-cookie-banner
      banner-id="YOUR_BANNER_ID"
      base-url="https://your-probo-instance.com/api/cookie-banner/v1/"
      position="bottom-left"
    />
  );
}
```

Then render it in your root layout:

```tsx
// src/app/layout.tsx

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        
      </body>
    </html>
  );
}
```

The `useConsent` hook works in any client component. Mark hooks that use it with `"use client"` or consume them from client components:

```tsx
// src/components/AnalyticsLoader.tsx
"use client";

export function AnalyticsLoader() {
  const consent = useConsent();

  if (!consent.analytics) {
    return null;
  }

  return ;
}
```

### Pages Router

In the Pages Router, the banner component works without `"use client"`. Render it in `_app.tsx`:

```tsx
// pages/_app.tsx

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      
      
    </>
  );
}
```

## Headless Components

For complete control over the consent UI in React, use the [headless components](/docs/product/cookie-banner/javascript-sdk#headless-components-full-control). Register them once and compose the Web Component building blocks in your JSX:

```tsx
"use client";

let registered = false;

export function CustomConsentBanner() {
  useEffect(() => {
    if (!registered) {
      registerHeadlessComponents();
      registered = true;
    }
  }, []);

  return (
    <>
      <probo-cookie-banner-root
        banner-id="YOUR_BANNER_ID"
        base-url="https://your-probo-instance.com/api/cookie-banner/v1/"
      >
        <probo-banner>
          <div className="my-banner">
            <p>We use cookies to improve your experience.</p>
            <probo-accept-button>
              <button>Accept all</button>
            </probo-accept-button>
            <probo-reject-button>
              <button>Reject all</button>
            </probo-reject-button>
            <probo-customize-button>
              <button>Customize</button>
            </probo-customize-button>
            <probo-acknowledge-button>
              <button>Got it</button>
            </probo-acknowledge-button>
          </div>
        </probo-banner>

        <probo-preference-panel>
          <div className="my-preferences">
            <probo-category-list>
              <template>
                <div className="category">
                  <span data-slot="name"></span>
                  <span data-slot="description"></span>
                  <probo-category-toggle>
                    <input type="checkbox" />
                  </probo-category-toggle>
                </div>
              </template>
            </probo-category-list>
            <probo-save-button>
              <button>Save preferences</button>
            </probo-save-button>
          </div>
        </probo-preference-panel>

        <probo-privacy-choices>
          <div className="my-privacy-choices">
            <probo-reject-button>
              <button>Do Not Sell or Share My Personal Information</button>
            </probo-reject-button>
          </div>
        </probo-privacy-choices>
      </probo-cookie-banner-root>

      <probo-settings-link>Cookie settings</probo-settings-link>
    </>
  );
}
```

Use `resolveLayout` / `resolveBannerText` from `@probo/cookie-banner/headless` to show the right controls for `OPT_IN`, `OPT_OUT`, or `NOTICE`. See the [JavaScript SDK](/docs/product/cookie-banner/javascript-sdk#headless-components-full-control) docs for the full component reference and [Layout API](/docs/product/cookie-banner/javascript-sdk#layout-api).

## Settings Link

Place `<probo-settings-link>` in your header or footer. It is required for all embeds — there is no floating settings button, and in opt-out jurisdictions it is the only banner surface a visitor ever sees.

```tsx
export function Footer() {
  return (
    <footer>
      <probo-settings-link>Cookie settings</probo-settings-link>
    </footer>
  );
}
```

Put your default label as children (shown for non-CCPA visitors). Under CCPA the SDK always replaces the content with the statutory “Your Privacy Choices” label and official opt-out icon, and opens the Privacy Choices panel. Style the host for font size and color:

```css
probo-settings-link {
  font-size: 14px;
  color: #334155;
  text-decoration: underline;
}
```

See [Settings link](/docs/product/cookie-banner/javascript-sdk#settings-link) for full behavior by regulation.
