# Introduction > BaseHub is a fast and collaborative Headless CMS. Welcome to BaseHub Docs. [Throughout this site](https://docs.basehub.com/nextjs-integration/start-here), you’ll find instructions on how to connect BaseHub to your website using our SDKs, and you’ll learn more about our platform and features. ## Popular Sections Jump straight into one of our most popular sections. [Next.js Integration(Get started with Next.js)](https://docs.basehub.com/documentation/nextjs-integration/start-here)[API Reference(Know how our APIs work)](https://docs.basehub.com/api-reference) ## Help Have a specific question or support request? These are our support channels: * X: [https://x.com/basehub\_ai](https://x.com/basehub_ai) * Discord: [https://discord.gg/6Gk4qfuqHK](https://discord.gg/6Gk4qfuqHK) * Help Center (live chat): [https://basehub.com/help?chat=true](https://basehub.com/help?chat=true) # Platform Overview > Understand the basics of the BaseHub Platform. BaseHub has three main properties: 1. The Dashboard, `basehub.com`, where you create teams, repositories, collaborate on content, etc 2. The GraphQ: API, `api.basehub.com`, where you interact with your repository programmatically, either to query data in your repo, or to mutate data in your repo 3. The SDK, which you install and run within your website: `pnpm i basehub` As you use BaseHub, you—or your team as a whole—will interact with all of these parts, and that’s why having a good understanding of the whole is important. ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2Fwj_i1gS0peoNRJ_wze9ig%2Fcleanshot-2024-05-24-at-16.56.032x.png&w=3840&q=75) ## Creating a Block Every piece of content you create in BaseHub is a Block. Similar to Lego, Blocks can have different types and functions. You can nest Blocks, reference Blocks, and more. In the Editor, you’ll create Blocks by typing `/` and choosing one Block type from the Block selector. Read more about Blocks in our Blocks Reference: [Blocks Reference(Deep dive into all of the different Blocks that are available in BaseHub.)](https://docs.basehub.com/blocks-reference) ## Committing A Commit stores a snapshot of your Repo at that specific point in time. Inspired by Git, each commit is immutable, and it’s a core of how version control works in BaseHub. Once you’re happy with your changes, you can create a Commit. The API will now use the latest commit (the Head Commit) to resolve your queries. ## Exploring the GraphQL API A great way to explore the GraphQL API is to use the Explorer. You can find it in the README: ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2F8wtk4c1elfoc9YISfo3Ei%2Fcleanshot-2024-05-24-at-17.17.072x.png&w=3840&q=75) # Start Here > Learn how to integrate your Next.js App with BaseHub in a couple of steps. ## Set Up `basehub` Our official JavaScript/TypeScript library exposes a CLI generator that, when run, will generate a type-safe GraphQL client. Check out [our API Reference](https://docs.basehub.com/api-reference/javascript-sdk) for more information. ### Install Install with your preferred package manager. npm ``` npm i basehub ``` ### Add the `BASEHUB_TOKEN` Environment Variable Get it from your BaseHub Repo’s README. .env.local ``` BASEHUB_TOKEN="" # Remember to also add this ^ env var in your deployment platform ``` ### Configure Node Scripts In order to generate the BaseHub SDK, we recommend running `basehub dev` in parallel to running the development server, and `basehub` right before building the app. package.json ``` "scripts": { "dev": "basehub dev & next dev", "build": "basehub && next build", "start": "next start", "lint": "next lint" }, ``` ### Start the Dev Server Give it a go to make sure the set up went correctly. npm ``` npm run dev ``` Now, let’s go ahead and query some content! ## Your First Query The recommended way to query content from BaseHub is with ``, a React Server Component that enables a Fast Refresh-like experience. app/page.tsx ``` import { Pump } from "basehub/react-pump" import { draftMode } from "next/headers" const Page = () => { return ( {async ([data]) => { "use server" return (
            {JSON.stringify(data, null, 2)}
          
) }}
) } export default Page ``` Notice we’re using Next.js’ `draftMode` and passing it down to Pump. You’ll learn more in the next section, but put briefly: when `draft === true`, Pump will subscribe to changes in real time from your Repo, and so keep your UI up-to-date. This is ideal for previewing content before pushing it to production. When `draft === false`, Pump will hit the Query API directly. # Querying Basics > Learn how to build GraphQL queries with the generated client. When you run `basehub`, you’ll be generating a GraphQL Client. What’s unique about this GraphQL client is that you’ll be defining the queries within your `.{js,ts}` files, instead of within `.graphql` ones. Most importantly, the output of your queries will be fully type safe. Getting runtime type safety is a huge DX boost. info: Under the hood, we use [https://genql.dev/](https://genql.dev/), so make sure you check out that project out. If you want to see how a GraphQL query converts to a GenQL query, you can [check out their converter tool](https://genql.dev/converter). ## `basehub()` This function let’s you fire off a single, direct query. Because of this, it’s perfect for **querying content that you don’t need to render**, like when defining `generateStaticParams` within a [dynamic Next.js page](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). ``` import { basehub } from "basehub" export const generateStaticParams = async () => { const { posts } = await basehub({ cache: "no-store" }).query({ posts: { items: { _slug: true } }, }) return posts.items.map((p) => { return { slug: p._slug } }) } ``` ## `` Pump can subscribe to realtime changes from your dashboard, and re-compute the JSX so that you can have a Fast Refresh-like experience. Because of this, Pump is ideal for querying content that you’ll want to render—for example, titles, images, rich texts, etc. ``` import { Pump } from "basehub/react-pump" import { draftMode } from "next/headers" const Page = () => { return ( {async ([data]) => { "use server" return (
            {JSON.stringify(data, null, 2)}
          
) }}
) } export default Page ``` note: Under the hood, Pump uses basehub() as its client. You can think of Pump is an abstraction over the more primitive basehub(), that helps you get that realtime editing experience. With these two ways of querying in mind, let’s explore how to build our queries. ## Anatomy of a Query Queries are JavaScript objects, where each key represents a key in the GraphQL schema, and the value is a boolean which decides weather you want to retrieve that key or not. Let’s take this query as an example: ``` import { basehub } from "basehub" basehub().query({ _sys: { id: true, }, homepage: { title: true, }, posts: { items: { _id: true, _slug: true, _title: true, publishedAt: true, }, }, }) ``` This query above will return the following result: GraphQL Output ``` query { _sys { id } homepage { title } posts { items { _id _slug _title publishedAt } } } ``` As you can see, GraphQL and TypeScript are not _that different_, and this is what our client is taking advantage of. ### Passing arguments You can pass down arguments with `__args`: ``` import { basehub } from "basehub" basehub().query({ posts: { __args: { filter: { _sys_slug: { eq: "my-post-slug" }, }, }, items: { _id: true, _slug: true, _title: true, publishedAt: true, }, }, }) ``` ### Fragmenting Fragments are very useful to define data dependencies inside your application. To define a fragment with our SDK, you’ll use `fragmentOn`: ``` import { basehub, fragmentOn } from "basehub" export const PostFragment = fragmentOn("PostItem", { _id: true, _slug: true, _title: true, publishedAt: true, }) // you can use it as a type as well export type PostFragment = fragmentOn.infer basehub().query({ posts: { __args: { filter: { _sys_slug: { eq: "my-post-slug" }, }, }, items: { _id: true, _slug: true, _title: true, publishedAt: true, ...PostFragment }, }, }) ``` #### Co-Locating Components with Their Data Dependency A common pattern we enjoy using revolves around components defining thier own data dependencies. This works great with fragments, as we can easily define a fragment alongside a component and have it all be type safe. ``` // Let's imagine a Callout component: import { fragmentOn } from ".basehub" import { RichText } from ".basehub/react-rich-text" export const CalloutFragment = fragmentOn("CalloutComponent", { _id: true, emoji: true, body: { json: { content: true } }, }) export const Callout = ({ data, }: { data: fragmentOn.infer }) => { return (
{data.emoji} {data.body.json.content}
) } ``` Then you could use this `CalloutFragment` paired with `` , all type safe and with the data dependency co-located. If you update your Callout component and require more data from BaseHub, you can update the fragment and you’ll instantly get the data coming via props. ### Not Supported: Aliases Aliases are a very useful GraphQL feature, which unfortunately is not currently supported. If you need this feature, contact us to help us prioritize. # Rendering Rich Text > Fragments let you construct sets of fields, and then include them in queries where you need to. The GraphQL API can return your Rich Text Blocks’ data in multiple formats: 1. **Plain Text**, will ignore all formatting, media, and custom components, easy to render. 2. **HTML**, will ignore custom components, easy to render. 3. **Markdown**, will ignore custom components, needs a markdown to HTML parser to render. 4. **JSON**, comes with everything, but needs something that understand and processes it. In the case of the JSON format, the response will be an AST based on the [TipTap editor spec](https://tiptap.dev/docs/editor/guide/output#option-1-json). Because of the complexities associated with processing this JSON format, we’ve built a React Component called `` that will help us render our Rich Text content. This is how it works: ``` import { Pump } from "basehub/react-pump" import { RichText } from "basehub/react-rich-text" const Page = async () => { return ( {async ([{ homepage }]) => { "use server" return {homepage.subtitle.json.content} }} ) } export default Page ``` ## Component Overrides When using the `` component, you can simply pass the JSON content into it via `children`, and it’ll get rendered. If you want to use a custom handler for a certain HTML node (imagine using Next.js’ `` to render images), you’d use the `components` prop. ``` import { Pump } from "basehub/react-pump" import { RichText } from "basehub/react-rich-text" import Image from "next/image" const Page = async () => { return ( {async ([{ homepage }]) => { "use server" return ( , }} > {homepage.subtitle.json.content} ) }} ) } export default Page ``` note: `` will return the HTML for each node of content, without any `
` wrapping everything nor any styles. We recommend using something like [Tailwind Typography](https://tailwindcss.com/docs/typography-plugin#installation) for quick prose styling, or of course, writing your own CSS. ## Custom Components If you are using [Custom Blocks in your Rich Text](https://basehub.com/changelog/instantiate-components-inside-rich-text-blocks), you’ll need to add them to your query, and pass them via the `blocks` prop. Then, you’ll be able to set up the custom renderers for them (in a type-safe manner, by the way): ``` import { Pump } from "basehub/react-pump" import { RichText } from "basehub/react-rich-text" import Image from "next/image" import { Callout, CodeSnippet } from './path-to/components' const Page = async () => { return ( {async ([{ homepage }]) => { "use server" return ( , CalloutComponent: (props) => , CodeSnippetComponent: (props) => , }} > {homepage.subtitle.json.content} ) }} ) } export default Page ``` We hope this removes a bit of friction from the sill tough task of rendering Rich Text data. # Environments & Caching > Understand the different environments and caching strategies you can leverage to improve your content editing experience. ## Environments Setting up your application so that it handles all of the environments in a seamless fashion is a very important part of integrating with BaseHub. ### Local Environment When developing in localhost, you’ll be writing new code and iterating over your content. This means adding new blocks, changing those blocks’ constraints, writing content and more—all at the same time. In order to _not break your flow_, you’ll want two things: 1. For the schema in BaseHub to be in sync with your IDE, and 2. For the content to update as you write, without needing to commit it yet. We bundled these two needs into one command: ``` basehub dev ``` This command generates the type-safe SDK and keeps it in sync with changes you make in basehub.com (this is called `--watch` mode); and also sets up the SDK so that it queries Draft content from your repository. This is why we recommend you run it _in parallel_ to `next dev`. ``` "scripts": { "dev": "basehub dev & next dev", "build": "basehub && next build", "start": "next start", "lint": "next lint" }, ``` _Notice the single_ `&`_._ ### Preview Environment Setting up an easy way for editors to preview content before committing it into production is essential. We’ve designed our preview workflow with these three pillars in mind: 1. Content should render in real time, as you write. 2. Preview should be easy for developers to integrate. 3. The integration should never degrade production performance _in any way_. We achieve this is by using a couple of BaseHub components, `` and ``, in combination to Next.js’ `draftMode`. Additionally, to bridge the gap between basehub.com (the dashboard) and your website, you’ll need to set up the “Preview” Button. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Description Author `` Queries the API. Receives a `draft` prop that controls weather it’ll hit draft content and subscribe to real time changes, or just hit production. BaseHub `draftMode` Allows you to detect Draft Mode inside a Server Component. Next.js `` Helper to turn on/off Draft Mode within your site, with zero-config. BaseHub Preview Button Links from a BaseHub block into where that block is being rendered in your website. BaseHub This is how a simple code example can look like: app/layout.tsx ``` import { Toolbar } from 'basehub/next-toolbar' export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( {/* Layout UI */}
{children}
) } ``` Finally, we need to set up our Preview Buttons. See how to set up Preview Buttons, and the whole preview environment really. ### Production Environment Once we’ve set up Local and Preview environments, most of the hard work is done. The only thing you need to make sure when going to production is for the SDK to be generated before the build step of your application. ``` "scripts": { "dev": "basehub dev & next dev", "build": "basehub && next build", "start": "next start", "lint": "next lint" }, ``` That should be it. You’re ready to deploy your website. ## Caching By default, [Next.js will try to cache all of our requests made with](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching) `fetch`—and that includes BaseHub. While this makes subsequent requests to BaseHub much faster, it’ll essentially make your website’s content fully static, instead of reflecting the latest content changes from your BaseHub Repo. This introduces a new task for the developer, which is to purge that cache when content from BaseHub changes. These are some of the options you have: ### On-Demand Revalidation (Recommended) The absolute best method of revalidation is “on-demand”. As its name implies, it consists of purging the cached data at the exact moment a change occurs. This provides the best experience for editors, as they won’t need to refresh the website for several seconds to see their content live; and also keeps server costs down, as the server itself won’t need to constantly check with our API to see if something has changed. BaseHub provides automatic on-demand revalidation in a fine-grained manner. * Automatic: without the need of constant developer setup. * Fine-grained: with every query being revalidated individually—in contrast to an “all or nothing” approach. This is how: ### Mount the in `layout.tsx` This will add a Server Action to revalidate the specific tags `basehub()` will set to each query. ``` // app/layout.tsx import { Toolbar } from "basehub/next-toolbar" export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( {/* Layout UI */}
{children}
) } ``` ### Fill in the Website URL input in BaseHub This will help our servers know where to go to to revalidate the queries. ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2F4dc74fb9bbf1a5d52c36b5649b537665%2Fcleanshot-2024-10-12-at-11.04.212x.png&w=3840&q=75) In the Readme, top right ### Just use it That should be all! Make sure you don’t pass other cache-related props (such as `revalidate` or `cache`), as that will opt the query out of automatic on-demand revalidation. As you may notice, we’re also not passing `draftMode().isEnabled` via props, as this is no longer required as of `basehub@7.5.10`—we now automatically infer draft mode for you. ``` import { Pump } from "basehub/react-pump" import { basehub } from "basehub" const Page = async () => { // works with basehub and with Pump const data = await basehub().query({ __typename: true }) return ( {async ([data]) => { "use server" return
{JSON.stringify(data, null, 2)}
}}
) } export default Page ``` info: Wondering **how does this all work?** When `basehub().query` is ran, we hash the query being sent and use it as a cache tag. We send this cache tag to our servers (alongside the query itself). The server now runs the query and computes the response. It will then hash the response, and store the cache tag, the original query, and the response hash in our database. On commit, we’ll get all of the queries we’ve been collecting and run them again against the newly committed tree of blocks. Now, one by one, we run them, compute the response hash, and compare it against the one we previously returned to the user. If response hashes don’t match, we need to revalidate the query. To revalidate the query, we spin up a headless browser that navigates to your Website URL and executes the Server Action our `` created. ### Time-Based Revalidation Another conventional way to revalidate content is to use Next.js’ [time-based](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#time-based-revalidation) `revalidate` [caching option](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#time-based-revalidation). ``` import { Pump } from "basehub/react-pump" const Page = async () => { return ( {async ([data]) => { "use server" // `data` will be stale after 30 seconds return
{JSON.stringify(data, null, 2)}
}}
) } export default Page ``` While this is very easy to set up, automatic on-demand revalidation is always better, as editors won’t need to refresh the website for several seconds to see their content live; will keep server costs down, as the server itself won’t need to constantly check with our API to see if something has changed; and will simply remove one task from developers’ hands. # Search > Learn how to add instant-search into your website. BaseHub Search will help you create instant-search experiences _ala_ Algolia inside your website. There are two steps into building an awesome search experience: 1. Indexing the content 2. Building the frontend BaseHub helps you with both of these tasks. ## Indexing the Content BaseHub Search supports indexing blocks that are below [Components](https://docs.basehub.com/blocks/layout/component). By default, blocks won’t be indexed. To index a block, you’ll go to over to its Properties Panel and click on the “Index block“ toggle. warning: The “Index block” state is set in a Component, and will be inherited by the Instances. Make sure you go to a Component to toggle this state. ### Indexing Happens On Commit In order for results to appear on your frontend, you’ll need to commit your changes. Toggling the “Index block” state is a “committable change.” Then, as you edit and add new content content, and commit, BaseHub Search will re-index and then your frontend will show the updated results. ## Building the Frontend There are a couple of ways in which BaseHub helps you build your search frontend. First, you’ll needit exposes a `useSearch` hook to make the queries and manage state. Second, it exposes a `` component that provides good UX defaults for you to render your search input, your results, and your highlights. In order for all of this to work, you’ll first need to get a `_searchKey` from the GraphQL API, which is scoped to a specific Collection or Component. ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2FakjRW8Uqoh1mCPovvPzyX%2Fcleanshot-2024-05-22-at-16.13.442x.png&w=3840&q=75) Simplified graph of how the flow works. Let’s imagine you have a Posts Collection and you want to build a frontend so search through it. ### Get a `_searchKey` This is how you’ll get your `_searcKey`: ``` import { Pump } from "basehub/react-pump" import { draftMode } from "next/headers" const Page = async () => { return ( {async ([data]) => { "use server" return ( <> ... ) }} ) } export default Page ``` ### Build your `` component You’re now ready to `useSearch` and `` to build your UI. ``` 'use client' import { useSearch, SearchBox } from "basehub/react-search" export const Search = ({ _searchKey, }: { _searchKey: string }) => { const search = useSearch({ _searchKey, queryBy: ["_title", "body", "excerpt"], }) return ( Start typing to search. Nothing found for {search.query} {search.result?.hits.map((hit) => { return ( ) })} ) } ``` ## Examples 1. Simple, non real-world example * GitHub Repo: [https://github.com/basehub-ai/nextjs-simple-search-example](https://github.com/basehub-ai/nextjs-simple-search-example/blob/main/app/page.tsx) * BaseHub Repo: [https://basehub.com/basehub/simple-search-example](https://basehub.com/basehub/simple-search-example) 2. Advanced example (the search that powers these docs) * GitHub Repo: [https://github.com/basehub-ai/nextjs-docs](https://github.com/basehub-ai/nextjs-docs/blob/main/app/_components/header/search/index.tsx) * BaseHub Repo: [https://basehub.com/basehub/docs](https://basehub.com/basehub/docs) Watch JB integrate a search experience from scratch # Analytics > Learn how to send analytics events from your website. BaseHub Analytics provides a simple, yet powerful, way to know more about how your content is performing. The unique thing about it is that Events that occur throughout your website can be tied directly to a Block—therefore keeping it in context. Analyitcs can be used for tracking things like: * Page views (internal and user facing) * Feedback forms * Button/Link Clicks Or anything you want, really. ## Send an Event In order to send an event, you’ll need to first get the `_analyticsKey` of a block from the GraphQL API. Let’s imagine we have a Posts collection and we’re rendering a specific post. Once we get the post data and its `_analyticsKey`, we’ll `import { sendEvent } from "basehub/analytics"` and run it on mount: Get post data ``` import { Pump } from "basehub/react-pump" import { notFound } from "next/navigation" import { draftMode } from "next/headers" const Page = () => { return ( {async ([data]) => { "use server" const post = data.posts.items[0] if (!post) notFound() return (

{post._title}

) }}
) } ``` ## Get an Event In case you want to show the Event Count in your website—for example, to render a “view count”—, well, you can! Following up from the `` component we built previously, we can update it so that it runs `getEventCount` and renders it: ``` "use client" import * as React from "react" import { sendEvent, getEventCount } from "basehub/analytics" export const PageView = ({ _analyticsKey, }: { _analyticsKey: string }) => { const [count, setCount] = React.useState() // On mount, send the event React.useEffect(() => { sendEvent({ _analyticsKey, name: "page_view" }) }, []) // We also get the event count so we can render it React.useEffect(() => { getEventCount({ _analyticsKey, name: "page_view" }).then( (count) => { setCount(count) }, ) }, []) return
Views: {count ?? "Loading..."}
} ``` ## See Events in Dashboard Now that you have the integration done, it’s time to see how those events come in. In order to do so, you’ll need to: 1. Select the Block you want to see Analytics for. 2. Click on “Analytics” in the Block Panel (top right next to “Properties”). # Webhooks > Learn how to use Webhooks to subscribe to changes that happen within BaseHub. Webhooks allow you to receive event notifications from BaseHub. BaseHub will send a POST request to a URL you specify when certain events happen in a BaseHub Repository. BaseHub processes webhooks with [Svix](https://www.svix.com/). The only supported webhook right now is `repo.commit`. This is a useful notification that can help you set up [on-demand revalidation for your Next.js Apps](https://docs.basehub.com/documentation/nextjs-integration/environments-and-caching#on-demand-revalidation), amongst other things. ## Webhook Portal To configure webhooks, navigate to a Repo, then to Connect, and then to Webhooks. You’ll see a dialog with a UI hosted by Svix that will let you manage webhooks for your Repository. This is the Webhook Portal. ## Basic Auth For extra security, it is recommended to pass in an `Authorization` header to the webhook endpoint. In the endpoint, you’d receive that header and validate it matches the password you’ve set up. ## Svix Auth Basic authentication (via `Authorization` header) is super simple and should work well for non-sensitive actions. If you want better security for your webhooks, you can follow [Svix’s Guide on how to verify webhook requests](https://docs.svix.com/receiving/verifying-payloads/how), and leverage the Signing Secret. ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F9dbc0da9%2Fwvi6f59jxang51m6yuvmygkk%2Fclean-shot-2024-01-28-at-14.16.28.png.png&w=3840&q=75) # Astro > Get started with Astro and BaseHub. [Astro](https://astro.build/) is a framework for performant, content-driven websites. With it, you can use almost any UI library you want to (React, Vue, Svelte, etc). note: The main difference that the setup Astro has vs Next.js is in the way it exposes environment variables. While in Next.js, `process.env.BASEHUB_TOKEN` is available for our SDK to use, in Vite-powered frameworks (like Astro), you’ll need to explicitly pass the token via params as you’ll see below. ## Set Up `basehub` Our official JavaScript/TypeScript library exposes a CLI generator that, when run, will generate a type-safe GraphQL client. Check out [our API Reference](https://docs.basehub.com/api-reference/javascript-sdk) for more information. ### Install Install with your preferred package manager. npm ``` npm i basehub ``` ### Add the `BASEHUB_TOKEN` Environment Variable Get it from your BaseHub Repo’s README. .env ``` BASEHUB_TOKEN="" # Remember to also add this ^ env var in your deployment platform ``` ### Configure Node Scripts In order to generate the BaseHub SDK, we recommend running `basehub dev` in parallel to running the development server, and `basehub` right before building the app. package.json ``` "scripts": { "dev": "basehub dev & astro dev", "start": "basehub dev & astro dev", "build": "basehub && astro check && astro build", "preview": "astro preview", "astro": "astro" }, ``` ### Start the Dev Server Give it a go to make sure the set up went correctly. npm ``` npm run dev ``` ## Your First Query Now, let’s go ahead and query some content! src/pages/index.astro ``` --- import { basehub } from 'basehub' const data = await basehub({ token: import.meta.env.BASEHUB_TOKEN }).query({ __typename: true, _sys: { id: true } }) --- Astro
{JSON.stringify(data, null, 2)}
``` ## Support Table While you can query BaseHub content from Astro, there are some DX features that are not supported. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Feature Supported `basehub()` ✅ `` ❌ `` ✅ (with React) Analytics ✅ Search ✅ (with React) # SvelteKit > Get started with SvelteKit and BaseHub. [SvelteKit](https://kit.svelte.dev/docs/introduction) is a framework for rapidly developing robust, performant web applications using [Svelte](https://svelte.dev/). note: The main difference that the setup SvelteKit has vs Next.js is in the way it exposes environment variables. While in Next.js, `process.env.BASEHUB_TOKEN` is available for our SDK to use, in Vite-powered frameworks (like SvelteKit), you’ll need to explicitly pass the token via params as you’ll see below. ## Set Up `basehub` Our official JavaScript/TypeScript library exposes a CLI generator that, when run, will generate a type-safe GraphQL client. Check out [our API Reference](https://docs.basehub.com/api-reference/javascript-sdk) for more information. ### Install Install with your preferred package manager. npm ``` npm i basehub ``` ### Add the `BASEHUB_TOKEN` Environment Variable Get it from your BaseHub Repo’s README. .env ``` BASEHUB_TOKEN="" # Remember to also add this ^ env var in your deployment platform ``` ### Configure Node Scripts In order to generate the BaseHub SDK, we recommend running `basehub dev` in parallel to running the development server, and `basehub` right before building the app. package.json ``` "scripts": { "dev": "basehub dev & vite dev", "build": "basehub && vite build", "preview": "vite preview", ... rest scripts }, ``` ### Start the Dev Server Give it a go to make sure the set up went correctly. npm ``` npm run dev ``` ## Your First Query Now, let’s go ahead and query some content! +page.server.ts ``` import type { PageServerLoad } from "./$types" import { basehub } from "basehub" import { BASEHUB_TOKEN } from "$env/static/private" export const load: PageServerLoad = async () => { const now = Date.now() const data = await basehub({ token: BASEHUB_TOKEN }).query({ __typename: true, _sys: { id: true, }, }) return data } ``` ## Support Table While you can query BaseHub content from SvelteKit, there are some DX features that are not supported. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Feature Supported `basehub()` ✅ `` ❌ `` ❌ Analytics ✅ Search ✅ (just the client, not the UI helpers) # CLI > Generates a type-safe client based on your Repo's schema. ## Generate ``` basehub generate ``` This command will get your BaseHub Token from your environment using [dotenv-mono](https://www.npmjs.com/package/dotenv-mono), use that to query the BaseHub API, and generate a type-safe SDK out of its schema. ### Arguments \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Description Default Required `--watch` Watch mode will listen to schema changes and re-generate the SDK automatically. `false` No `--output` Specifcy a different location for the generated output. `.basehub` No `--env-prefix` Specify a different prefix for [relevant environment variables](#relevant-environment-variables). `BASEHUB_` No `--draft` Draft mode will query draft (non-committed) content from the GraphQL API. `false` No ### Aliases \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Command Description `basehub` Same as running `basehub generate [...args]` `basehub dev` Same as running `basehub generate --watch --draft [...args]` ### Relevant Environment Variables \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Description Required `TOKEN` A Repo’s read or write token. Yes `REF` Draft mode will query draft (non-committed) content from the GraphQL API. No ## Dev ``` basehub dev ``` The `dev` command is very useful for local development. It basically runs `basehub generate --watch --draft [...args]` (notice how watch and draft mode are both being forced). # query > The main method to consume data from your BaseHub repositories. ``` import { basehub } from 'basehub' basehub().query({ }) ``` When your token is setup, `basehub.query()` will query the data from the token’s repository.  Inside the query object, you can pass any parameter that the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) allows. That includes the [Next.js revalidate parameters](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate). You can check out its usage in the [GraphiQL Explorer](https://docs.basehub.com/api-reference/graphql-api/explorer) linked to your schema. Our `` [component](https://docs.basehub.com/api-reference/javascript-sdk/react/pump-component) uses `basehub.query()` behind the scenes to retrieve the data, that’s way its props are so similar. The great advantage `` has it’s that it will stream your updates in real time while on draft mode. ## Examples Let’s see some common query patterns. Remember, the specific query keys you use will depend on your repository's structure, not on static API definitions. ### Get a document block ``` basehub().query({ homepage: { title: true, description: { json: { content: true }, }, }, }) ``` ### Get a list of posts ``` basehub().query({ posts: { items: { _id: true, _title: true, _slug: true, // more fields here... }, }, }) ``` ### Get the first item in a list ``` basehub().query({ posts: { __args: { first: 1 }, items: { _id: true, _title: true, _slug: true, // more fields here... }, }, }) ``` ### Filter by `_slug` ``` basehub().query({ posts: { __args: { first: 1, filter: { _sys_slug: "your-post-slug" }, }, items: { _id: true, _title: true, _slug: true, // more fields here... }, }, }) ``` ### Order by created date ``` basehub().query({ posts: { __args: { orderBy: "_sys_createdAt__DESC", }, items: { _id: true, _title: true, _slug: true, // more fields here... }, }, }) ``` ### Create and use a fragment ``` import { basehub, fragmentOn } from "basehub" const buttonFragment = fragmentOn("ButtonComponent", { label: true, href: true, variant: true, }) basehub().query({ homepage: { title: true, description: { json: { content: true }, }, cta: buttonFragment, }, }) ``` ### Query a union ``` basehub().query({ dynamicPages: { items: { pathname: true, sections: { __typename: true, // required on_HeroSectionComponent: { title: true, subtitle: true, // more fields }, on_FeatureSectionComponent: { title: true, subtitle: true, // more fields }, }, }, }, }) ``` # mutation > The SDK method to make updates to your repository via the API. ``` import { basehub } from 'basehub' basehub().mutation({ }) ``` The `basehub.mutation()` lets you send GraphQL mutations to the BaseHub API using any JavaScript framework. This is useful for mutating data from your app into your BaseHub Repo. You can check out its usage in the [GraphiQL Explorer](https://docs.basehub.com/api-reference/graphql-api/explorer) linked to your schema. ## Methods The `mutation` API works a bit different to the `query` API due to how GraphQL is designed. `basehub().mutation()` has other methods to add data into BaseHub, the most important one being [transaction](https://docs.basehub.com/api-reference/javascript-sdk/basehub-client/mutation/transaction). # transaction > The main mutation method, covers most of the modifications that can be done to the BaseHub’s schema with three different transaction types: create, update and delete. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Transaction Type Arguments Type Description Create `parentId` `string` The block ID to target, where the data will be injected `data` `Object` The block values to be inserted, `type` is mandatory and will constraint the object type to the specific block schema `type` `”create”` The transaction type Delete `id` `string` The block ID to delete `type` `”delete”` The transaction type Update `data` `Object` Very similar to `create` data, but has an extra mandatory field `id` that maps to the existing block that will be updated `type` `”update”` The transaction type ## Example Check out our Mutation API Playground for full examples. * [Playground](https://mutation-api-playground.vercel.app/). * [Source](https://github.com/basehub-ai/mutations-api-example). * [Content](https://basehub.com/basehub/mutation-api-playground/explore). ## Create When running the create transaction, you will need to pass two additional parameters: `parentId` and `data`. The `parentId` is the ID from the block where the creation will be done, could be any block, but that will affect which data structures are valid. In the example above, using that specific `parentId` we cannot insert anything apart from instances, because collection children are always instances (or a component that works as template). The `data` field is the new block schema and values, including all its children. ## Automatic Commit The `autoCommit` is an optional field that accepts any `string` as the commit message that will be injected into the repository history. If not provided, the mutation updates will stay as work in progress (you will see them listed in your Changes Tab). # transactionAwaitable > Same as \`transaction\`, but waits until it's resolved. This method has the same signature as [transaction](https://docs.basehub.com/api-reference/javascript-sdk/basehub-client/mutation/transaction). It’s very useful if you want to wait until the transaction is resolved to know for sure if it succeeded or failed. ## Example Check out our Mutation API Playground for full examples. * [Playground](https://mutation-api-playground.vercel.app/). * [Source](https://github.com/basehub-ai/mutations-api-example). * [Content](https://basehub.com/basehub/mutation-api-playground/explore). # getUploadSignedURL > A helper to upload assets to our database. This is useful for example, when we have a PNG on our machine that we want to use in a BaseHub Image block. In order to use it, you should: ### Call the `getUploadSignedURL` mutation You will need to retrieve both the `signedURL` and the `uploadURL`. ### Do a PUT request to the `signedURL` The `signedURL` is an authorized endpoint that allows you to send any allowed asset through it. You’ll use it to upload the files you want to use in your BaseHub blocks. ### Consume the uploaded data from `uploadURL` The `uploadURL` is the path to the uploaded file. After sending the asset data to the `signedURL`, you will be able to see the file in this URL. You will use it in the block value when running a transaction mutation. ## Example On this example we’re uploading a new image file to BaseHub assets pool. You can explore the full code for this example in [Github](https://github.com/basehub-ai/mutations-api-example/blob/c4d1ccd2609598f707d58204ade29134fd283d8f/lib/mutate-action.ts#L16-L40). ``` export const uploadImageToBaseHub = async (imageInput: File) => { const { getUploadSignedURL } = await basehub().mutation({ getUploadSignedURL: { __args: { fileName: imageInput.name, }, signedURL: true, uploadURL: true, }, }); const uploadStatus = await fetch(getUploadSignedURL.signedURL, { method: "PUT", body: imageInput, headers: { "Content-Type": imageInput.type, }, }); if (uploadStatus.ok) { return getUploadSignedURL.uploadURL; } return null; }; ``` # transactionStatus > Gets the current transaction status based on its ID. ## Example You can explore the full code for this example in [Github](https://github.com/basehub-ai/mutations-api-example/blob/c4d1ccd2609598f707d58204ade29134fd283d8f/lib/mutate-action.ts#L4-L14). ``` export async function getStatus(id: string) { const response = await basehub().mutation({ transactionStatus: { __args: { id, }, }, }); return response.transactionStatus; } ``` # > A React Server Component that queries BaseHub and can subcribe to real time changes seamlessly. ``` import { Pump } from 'basehub/react-pump' ``` Pump is a React Server Component, meaning, it can only be used within frameworks that support RSC ([Next.js only for now](https://react.dev/learn/start-a-new-react-project#bleeding-edge-react-frameworks)). The power of Pump comes when you use [Next.js Draft Mode](https://nextjs.org/docs/app/building-your-application/configuring/draft-mode) alongside it. Pump lets developers write their queries and rendering logic in a simple and typesafe way, and get “content fast refresh” (live preview) out of the box, without affecting the website’s performance in any way. info: If you’re interested in how this works under the hood, or the reason behind its syntax, you can [read our blog post about it](https://basehub.com/blog/pump). ## Props These are the props supported by `` . \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Type Description `queries` `QueryType[]` **Required.** An array of BaseHub queries that will be fetched from the BaseHub API asynchronously `draft` `boolean` If enabled, it will fetch from the draft API, what consumes the WIP data. `token` `string` Lets you pass a BaseHub token explicitly. Useful for frameworks in which `process.env.BASEHUB_TOKEN` is not available. `signal` `AbortSignal` Inherited from the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). `next` `NextFetchCache` [Next.js only](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate). Let’s you configure the cache. `cache` `RequestCache` Inherited from the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). ## Example This query will get `_sys.id` from the API. Most importantly, when Next.js Draft Mode is enabled, it’ll subscribe to content changes in real time. ``` import { Pump } from "basehub/react-pump" import { draftMode } from "next/headers" const Page = () => { return ( {async ([data]) => { "use server" return (
            {JSON.stringify(data, null, 2)}
          
) }}
) } export default Page ``` # > Our official rich text renderer. Supports passing custom handlers for native html elements and BaseHub components. ``` import { RichText } from 'basehub/react-rich-text' ``` A React Component that understands Rich Text Blocks’ data model and helps you render them in your website. If used in frameworks that support server components, it can be used as a RSC and just render the final result in the client without sending all the bundle to the client. ## Props These are the props supported by `` \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Type Description `content` `Node[]` **Required.** The JSON formatted content from the BaseHub RichText field. Accesible via `…json.content` `blocks` `Blocks[]` The list of blocks present in the content. Accesible via `…json.blocks` `components` `Handlers` Custom handlers for native elements (such as `h1`, `p`, `img`) or custom components. note: When you provide the value for the `content` property, the RichText component will retrieve your schema types and give you type-safety and auto-complete for the `components` property. ## Example ``` import { Code, Heading, Link } from '@radix-ui/themes' import NextLink from 'next/link' export const ArticleBody = (props: ArticleFragment) => { return ( ( {children} ), h2: ({ children }) => ( {children} ), h3: ({ children }) => ( {children} ), a: ({ children, ...rest }) => ( {children} ), // Custom component CodeSnippetComponent: ({ children, isInline }) => { if (!isInline) return null return {children} }, }} /> ) } ``` ## Styling The `` component doesn’t come with styles. It's job is to render the html notes, but you'll need to add the styles yourself. This is intentional, as websites often vary a lot between typographies, colors, and sizes. there are a couple ways to style a rich text: 1. Use regular CSS 2. Use the [tailwindcss-typography](https://github.com/tailwindlabs/tailwindcss-typography) plugin (recommended) 3. Override each of the nodes with your own components Moreover, all of these methods can be combined as you please. ### 1\. Just CSS As an example: components/post-body.module.css ``` .post-body > *:first-child { margin-top: 0; } .post-body > *:last-child { margin-bottom: 0; } .post-body p { margin-bottom: 1em; } .post-body h1 { font-size: 2em; margin: 1.5em 0 0.5em; } .post-body h2 { font-size: 1.8em; margin: 1.4em 0 0.4em; } .post-body h3 { font-size: 1.4em; margin: 1.3em 0 0.3em; } .post-body ul, .post-body ol { margin: 0 0 1em 1.5em; } .post-body li { margin-bottom: 0.5em; } .post-body img { max-width: 100%; height: auto; margin: 1em 0; } .post-body blockquote { border-left: 4px solid #ddd; padding-left: 1em; margin: 1em 0; font-style: italic; color: #666; } .post-body pre { background-color: #f4f4f4; padding: 1em; overflow-x: auto; margin: 1em 0; } .post-body code { background-color: #f4f4f4; padding: 0.2em 0.4em; border-radius: 3px; } ``` ### 2\. With tailwind-typography (recommended) Assuming you’re already using tailwind, using the typography plugin is fairly simple. ``` pnpm i @tailwindcss/typography --save-dev ``` Then in `tailwind.config.js` ``` /** @type {import('tailwindcss').Config} */ module.exports = { theme: { // ... }, plugins: [ require('@tailwindcss/typography'), // ... ], } ``` And finally, you’ll use the `prose` class in the wrapping `
` ``` import { RichText } from "basehub/react-rich-text" const PostBody = (props) => { return (
) } ``` ### 3\. Overriding / Using your own design system If you already have components to render quotes, headings, paragraphs, etc, you can easily use them like this: ``` import { RichText } from "basehub/react-rich-text" import { Heading, Blockquote, Paragraph, } from "@my-design-system" const PostBody = (props) => { return (
, h1: (props) => , h2: (props) => , h3: (props) => , blockquote: (props) =>
, // rest... }} />
) } ``` Example: [https://github.com/basehub-ai/docs-template/blob/main/app/\_components/article/index.tsx#L182](https://github.com/basehub-ai/docs-template/blob/main/app/_components/article/index.tsx#L182) ## Custom Components If you are using [Custom Blocks in your Rich Text](https://basehub.com/changelog/instantiate-components-inside-rich-text-blocks), you’ll need to add them to your query, and pass them via the `blocks` prop. Then, you’ll be able to set up the custom renderers for them (in a type-safe manner, by the way): ``` import { Pump } from "basehub/react-pump" import { RichText } from "basehub/react-rich-text" import Image from "next/image" import { Callout, CodeSnippet } from './path-to/components' const Page = async () => { return ( {async ([{ homepage }]) => { "use server" return ( , CalloutComponent: (props) => , CodeSnippetComponent: (props) => , }} > {homepage.subtitle.json.content} ) }} ) } export default Page ``` # > Easy-to-use component for rendering great code snippets. ``` import { CodeBlock } from 'basehub/react-code-block' ``` There are many syntax highlighting libraries in the JavaScript ecosystem. While this is a good thing, it can be exhausting for developers to shop for the right one. Prism, highlight.js, and Shiki are the most popular ones—an, in our opinion, Shiki is the best. After building multiple websites with syntax highlighting, we’ve found ourselves copy-pasting a bunch of code and needing to re-read documentation over and over again. This is why we’ve built this. ## Props These are the props supported by `` \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Name Type Description `snippets` `Node[]` **Required.** The JSON formatted content from the BaseHub RichText field. Accesible via `…json.content` `theme` `Blocks[]` The list of blocks present in the content. Accesible via `…json.blocks` `childrenTop` `Handlers` Custom handlers for native elements (such as `h1`, `p`, `img`) or custom components (using the component API Typename) ## Basic Usage ``` import { CodeBlock } from 'basehub/react-code-block' const Post = () => { return ( ) } ``` ## CSS Theme ``` import { CodeBlock } from 'basehub/react-code-block' const Post = () => { return ( ) } ``` ## Examples * From our docs: [https://github.com/basehub-ai/docs-template/blob/main/app/\_components/article/code-snippet/index.tsx#L21](https://github.com/basehub-ai/docs-template/blob/main/app/_components/article/code-snippet/index.tsx#L21) * From the marketing website template: [https://github.com/basehub-ai/marketing-website-template/blob/main/src/app/\_components/code-snippet/index.tsx](https://github.com/basehub-ai/marketing-website-template/blob/main/src/app/_components/code-snippet/index.tsx) # useSearch > A React hook that instantiates your Search Client. ``` import { useSearch } from 'basehub/react-search' ``` ## Arguments \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `_searchKey` `string` **Required.** The search key from the block where you want to do search. The client will have access to all indexed fields under the corresponding block (and its instances in a case of a component). `queryBy` `string[]` **Required.** An array with the field keys you want to search by. `saveRecentSearches` `SaveRecentSearches` An object that accepts a `key` and a `getStorage` callback. Useful when you want to save recent searches into localStorage or similar. info: BaseHub Search uses [TypeSense](https://typesense.org/) on the background. **You can check out all the search options on their** [**documentation**](https://typesense.org/docs/26.0/api/search.html#search)**.** Keep in mind that they’re all on _camelCase_ in the `useSearch` hook. E.g: `filter_by` is listed as `filterBy`. ## Examples * Documentation: [Step by step](https://docs.basehub.com/extras/search#building-the-frontend) * Also you can check out our search implementation for this Documentation template [on GitHub](https://github.com/basehub-ai/nextjs-docs/blob/main/app/_components/header/search/index.tsx) # > The Search wrapper works as a provider and comes with some optional props that can come in handy. ``` import { SearchBox } from 'basehub/react-search' // -> SearchBox.Root ``` ## Props \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `search` `UseSearchResult` **Required.** The search client generated with [useSearch](https://docs.basehub.com/api-reference/javascript-sdk/react/search/usesearch). `onHitSelect` `(hit: Hit) => void` Optional callback triggered on any hit selection. ## Examples * Documentation: [Step by step](https://docs.basehub.com/extras/search#building-the-frontend) * Also you can check out our search implementation for this Documentation template [on Github](https://github.com/basehub-ai/nextjs-docs/blob/main/app/_components/header/search/index.tsx) # > Extends the native HTML Input and consumes the search context in order to fetch hits from the indexed data. ``` import { SearchBox } from 'basehub/react-search' // -> SearchBox.Input ``` ## Props The `` extends the native `HTMLInputProps`. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `asChild` `boolean` Passes all its configuration to the immediate child. It’s a requirement for this that it has only one children. ## Examples * Documentation: [Step by step](https://docs.basehub.com/extras/search#building-the-frontend) * Also you can check out our search implementation for this Documentation template [on Github](https://github.com/basehub-ai/nextjs-docs/blob/main/app/_components/header/search/index.tsx) # Hit Components > Use cases and APIReference for HitList, HitItem, HitSnippet ## Props ``` import { SearchBox } from 'basehub/react-search' // -> SearchBox.HitList ``` \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `asChild` `boolean` Passes all its configuration to the immediate child. It’s a requirement for this that it has only one children. ## Props ``` import { SearchBox } from 'basehub/react-search' // -> SearchBox.HitItem ``` The `` extends the native `HTMLDivProps`. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `asChild` `boolean` Passes all its configuration to the immediate child. It’s a requirement for this that it has only one children. `hit` `Hit` The hit element from the search results. `href` `string` The link to the hit result, can be any string, but most often than not, you will use the hit result to build the final URL. check: Both HitList and HitItem provide keyboard navigation out-of-the-box. ## Props ``` import { SearchBox } from 'basehub/react-search' // -> SearchBox.HitSnippet ``` The HitSnippet works as sugar syntax to render specific fields of the hit object with ease. \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `fieldPath` `string` **Required.** The specific field name in the hit object. e.g: `_title` `fallbackFieldPaths` `string[]` If the `fieldPath` is `undefined` or doesn’t have a match with the query, you can provide a list of fallback paths to render in its place. `components` `{ container, mark, text }` An optional set of react elements that can be passed to customize the final UI for the snippet. # sendEvent > The analytics method to send any event through BaseHub. Flexible, scoped by block. ``` import { sendEvent } from 'basehub/analytics' ``` ## Parameters \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `name` `string` **Required.** The event unique name, it can be any string. `_analyticsKey` `string` **Required.** The targeted block analytics key. `metadata` `Record` Optional metadata, can be any valid JSON object. It won’t be displayed in the current analytics implementation, but it’s stored in the event object in the background. ## Example ``` 'use client' import { sendEvent } from 'basehub/analytics' import { Card, IconButton } from '@radix-ui/themes' import { ThumbsDown, ThumbsUp } from 'lucide-react' import * as React from 'react' export const Feedback = ({ analyticsKey: _analyticsKey, }: { analyticsKey: string }) => { const [sentFeedback, setSentFeedback] = React.useState< 'positive' | 'negative' | null >(null) const handleFeedback = (type: 'positive' | 'negative') => { if (sentFeedback === type) return sendEvent({ _analyticsKey, name: `feedback:${type}` }) setSentFeedback(type) } return ( handleFeedback('negative')}> handleFeedback('positive')}> ) } ``` # getEventCount > Analytics method to retrieve the total count of a specific event. ``` import { getEventCount } from 'basehub/analytics' ``` ## Parameters \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `name` `string` **Required.** The event unique name, it can be any string. `_analyticsKey` `string` **Required.** The targeted block analytics key. ## Example ``` import { getEventCount } from 'basehub/analytics' import { IncrementViews } from './increment-views' import { unstable_noStore } from 'next/cache' import { draftMode } from 'next/headers' export const ViewsFragment = async ({ _analyticsKey, increment, }: { _analyticsKey: string increment?: boolean }) => { unstable_noStore() const { isEnabled: isDraftMode } = draftMode() const views = await getEventCount({ _analyticsKey, name: 'view' }) return ( <> {views || '0'} {increment && !isDraftMode && ( )} ) } ``` # search > Core method to perform a search query. ``` import { search } from 'basehub/search' ``` info: Using React? Check out our [React helpers right here](https://docs.basehub.com/api-reference/javascript-sdk/react/search). ## Arguments \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `_searchKey` `string | null` The search key (comes from the GraphQL API). `query` `string` The query (typically comes from user input). `options` `SearchOptions` Stuff like `queryBy`, `filterBy`, and more. # getClientRaw > Get the raw search client. ``` import { getSearchClientRaw } from 'basehub/search' ``` info: Using React? Check out our [React helpers right here](https://docs.basehub.com/api-reference/javascript-sdk/react/search). ## Arguments \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `_searchKey` `string | null` The search key (comes from the GraphQL API). # > The official BaseHub toolbar to manage draft mode and switch branches in your site previews. ``` import { Toolbar } from 'basehub/next-toolbar' ``` The Toolbar takes care of setting and managing the draftMode key without any other configuration or manual fetch to the BaseHub API. ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2FFd2hLFehKGMaIrJnwsjH5%2Fscreenshot-2024-06-11-at-18.56.51.png&w=3840&q=75) Toolbar - Draft Mode Enabled ![](/_next/image?url=https%3A%2F%2Fbasehub.earth%2F7b31fb4b%2FKfTDhoUO7Bm2KxDEdB3gY%2Fscreenshot-2024-06-11-at-18.57.01.png&w=3840&q=75) Toolbar - Draft Mode disabled ## Props \[data-radix-scroll-area-viewport\]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}\[data-radix-scroll-area-viewport\]::-webkit-scrollbar{display:none} Key Type Description `forceDraft` `boolean` Will force the draft mode for the entire site when present. ## Example ``` import { Toolbar } from 'basehub/next-toolbar' export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode }>) { return (
{children}