KATLA FOR REACT
Consent that lives in your component tree.
A provider, a handful of typed hooks and two unstyled components. The decision is state your components read and re-render on, the cookie guard is injected for you, and the banner is yours to restyle or replace outright.
@katla.app/sdk/reactReact 18 and 19Vite, CRA, any bundler
src/App.tsxVite + React
import { useEffect } from 'react'
import {
KatlaProvider,
CookieBanner,
useKatlaConsent,
} from '@katla.app/sdk/react'
function Analytics() {
const { consent } = useKatlaConsent()
useEffect(() => {
if (consent?.analytics) loadAnalytics()
}, [consent])
return null
}
export default function App() {
return (
<KatlaProvider siteId="your-site-id" googleConsentMode>
<Analytics />
<CookieBanner />
</KatlaProvider>
)
}The provider injects the cookie guard and the consent bridge itselfFull guide →
WHY REACT SITES STRUGGLE WITH CONSENT
Consent state and React state are the same problem, solved twice.
THE PROBLEMThe banner is a third-party script that mutates the DOM from outside React, and a re-render or a route change puts it back the way it was.
WITH KATLAA provider and typed hooks instead. Consent lives in context, and the components that read it re-render like anything else in your tree.
THE PROBLEMTags are loaded from index.html before React has mounted, so the decision arrives long after the cookies did.
WITH KATLAKatlaProvider injects the cookie guard as it mounts. A cookie whose category has not been granted is refused at document.cookie, whichever tag tried to set it.
THE PROBLEMA hosted banner ignores your design system, and restyling it is a fight with someone else's stylesheet.
WITH KATLACookieBanner ships no CSS — semantic markup with stable katla-* class names, a render prop that replaces it outright, and useConsentManager() if you want no markup at all.
SETUP
Four steps, one provider.
- Installnpm install @katla.app/sdk. About 5 KB over the wire in headless mode.
- Wrap your appPut KatlaProvider around your tree with your site ID, and add googleConsentMode if you run GA4 or Google Ads.
- Gate your tagsRead useKatlaConsent() and load analytics or marketing scripts only once their category is granted.
- Ship a bannerDrop in CookieBanner and style it with your own CSS, or build your own from useConsentManager().
BUILT FOR REACT
Hooks and components, and nothing you did not ask for.
useKatlaConsentThe current decision per category, updated in real time from window.KatlaConsent, with an onChange subscription that hands back its own unsubscribe.
useKatlaCookiesYour scanned inventory with loading and error states. In-flight requests are deduplicated, so ten components mounting at once still make one fetch.
useConsentManagerThe whole banner as state — ready, hasDecision, availableCategories, toggleCategory, acceptAll, rejectAll, saveSelection — and not a single element rendered.
Unstyled componentsCookieBanner and CookieCatalog render semantic HTML with katla-* class names, a render prop, and per-category and per-cookie overrides.
Consent Mode v2One googleConsentMode prop drives ad_storage, analytics_storage, ad_user_data and ad_personalization. Denied by default, updated on the decision.
Nothing fetched on mountkatla pull writes the inventory and the guard into .katla/. Pass them as initialCookies and guardScript and the browser requests nothing at all.
CORE WEB VITALS
That's how the cookie crumbles. Except your SEO shouldn't.
The consent script is the first third party on the page, which is why it turns up in the Core Web Vitals report. The React entry point is 5 KB over the wire, renders no interface you have not asked for and reserves no space in flow — and with initialCookies from the build, it makes no request at all.
How headless mode works →5 kBOver the wireGuard and consent API, brotli
0 msAdded LCPAgainst the same page without it
0Layout shiftThe banner reserves no space in flow
1RequestOne script, cached at the edge
Our own measurements, taken — how they were taken.
Questions React teams ask
- Should I use this in Next.js?
- Use @katla.app/sdk/next instead. KatlaNextProvider carries the client boundary so the rest of your tree stays Server Components, and getCachedCookies() prefetches the inventory on the server. The hooks and components are the same ones.
- Do I have to use CookieBanner?
- No. It takes a render prop that replaces its markup entirely, and useConsentManager() gives you the same state with no markup at all. The provider renders no banner on its own.
- Which versions of React?
- 18 and 19, as a peer dependency. Hooks and function components throughout, so it works with Vite, Create React App or any other client-side React setup.
- Can I avoid the request on page load?
- Yes. katla pull writes the cookie data, the policies and guard.js into .katla/ at build time. Pass them to the provider as initialCookies and guardScript and nothing is fetched at page load.
Wrap your app once, and the cookies wait their turn.
The free plan scans your React site and generates a cookie policy, without a card.