This is the abridged developer documentation for React Bricks # Admin > The Admin component should wrap all the components used in the Admin Interface. The Admin component **should wrap all the components used in the Admin Interface**, which are: - [`Login`](/api-reference/components/login) - [`Editor`](/api-reference/components/editor) - [`Playground`](/api-reference/components/playground) - [`AppSettings`](/api-reference/components/app-settings) It manages authentication and renders the Admin menu. It acts also as a Provider for the [AdminContext](/api-reference/hooks/use-admin-context), making it available to the wrapped components. ## Props ```tsx interface AdminProps { isLogin?: boolean isPublicDesignSystem?: boolean designSystemTitle?: string } ``` ## Properties definition | Property | Definition | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `isLogin` | Default `false`. It is boolean value to identify the Login page. It is needed to correctly manage the authentication process. | | `isPublicDesignSystem` | If true, the playground is accessible without authentication, in order to use it as a public design system documentation. | | `designSystemTitle` | Title to show in the playground page, if it is a public design system page. | ## Usage example, editor page ```tsx import React from 'react' import { Admin, Editor } from 'react-bricks' const EditorPage = () => { return ( ) } export default EditorPage ``` ## Usage example, login page ```tsx {6} import React from 'react' import { Admin, Login } from 'react-bricks' const LoginPage = () => { return ( ) } export default LoginPage ``` # AppSettings > Component that renders the AppSettings page in the Admin Interface. This component **renders the Settings page** in the [Admin Interface](/basics/admin-interface). The Settings page is where you can **trigger the build webhooks** if you are using a static website generator and access the dashboard to configure the project. It needs no props, but it must be wrapped by the [Admin](/api-reference/components/admin) component to receive the needed context. The route where this component is shown has to be specified in [ReactBricks](/api-reference/components/react-bricks)'s [configuration](/common-tasks/customize-react-bricks/) parameter `appSettingsPath`. ## Usage example ```tsx {2,7} import React from 'react' import { Admin, AppSettings } from 'react-bricks' const AppSettingsPage = () => { return ( ) } export default AppSettingsPage ``` # Editor > Component that renders the Editor page in the Admin Interface. This component **renders the Editor page** in the [Admin Interface](/basics/admin-interface#editor). The Editor is where you **edit your page content**. It needs no props, but it must be wrapped by the [Admin](/api-reference/components/admin) component to receive the needed context. The route where this component is shown has to be specified in [ReactBricks](/api-reference/components/react-bricks)'s [configuration](/common-tasks/customize-react-bricks) parameter `editorPath`. ## Usage example ```tsx {2,7} import React from 'react' import { Admin, Editor } from 'react-bricks' const EditorPage = () => { return ( ) } export default EditorPage ``` # Login > Component that renders the Login page in the Admin Interface. This component **renders the Login page** in the [Admin Interface](/basics/admin-interface). It needs no props, but it must be wrapped by the [Admin](/api-reference/components/admin) component to receive the needed context. The route where this component is shown has to be specified in [ReactBricks](/api-reference/components/react-bricks)'s [configuration](/common-tasks/customize-react-bricks/) parameter `loginPath`. ## Usage example ```tsx {2,7} import React from 'react' import { Admin, Login } from 'react-bricks' const LoginPage = () => { return ( ) } export default LoginPage ``` # PageViewer > The component that renders a page on the front-end exactly as you can see it in the Admin Interface. The PageViewer component is used on your website's public pages. It is the component that **renders a page on the front-end** exactly as you can see it in the Admin Interface, but with React Bricks visual edit components (Text, RichText, Image, File, Repeater) **in read-only mode**. ## Props ```tsx interface PageViewerProps { page: types.Page | null | undefined main?: boolean } ``` The PageViewer component has just one required prop: `page`. It is the page object you get from React Bricks APIs, using [`usePage`](/api-reference/hooks/use-page-public) or [`fetchPage`](/api-reference/utilities/fetch-page). Before passing the page object to `PageViewer`, you need to parse it with the [`cleanPage`](/api-reference/utilities/clean-page) utility function, which checks incoming blocks from the DB against your bricks schema. `main` is `true` by default. It enables the "click to edit" feature for this Page Viewer, regardless of the [`clickToEditSide` configuration](/common-tasks/customize-react-bricks/). This is useful when you have multiple PageViewers on a page (for example for page content, header and footer) to choose which PageViewer is the "main" one that defines the slug to be edited with the icon. Previously this parameter was called `showClickToEdit`. ## Usage example, with usePage hook ```tsx {12} import React, { useContext } from 'react' import { PageViewer, usePage, cleanPage, ReactBricksContext, } from 'react-bricks/frontend' const Viewer = () => { const { data } = usePage('home') const { pageTypes, bricks } = useContext(ReactBricksContext) // Clean the received content // Removes unknown or not allowed bricks const page = cleanPage(data, pageTypes, bricks) return } export default Viewer ``` ## Usage example, with fetchPage ```tsx {16} import React, { useState, useContext, useEffect } from 'react' import { PageViewer, fetchPage, cleanPage, ReactBricksContext, } from 'react-bricks/frontend' const ViewerFetch = () => { const [page, setPage] = useState(null) const { apiKey, blockTypeSchema, pageTypeSchema } = useContext(ReactBricksContext) useEffect(() => { fetchPage('home', apiKey).then((data) => { const myPage = cleanPage(data, pageTypeSchema, blockTypeSchema) setPage(myPage) }) }, [apiKey, pageTypeSchema, blockTypeSchema]) if (page) { return } return null } export default ViewerFetch ``` # Playground > Component that renders the Playground page in the Admin Interface. This component **renders the Playground page** in the [Admin Interface](/basics/admin-interface#playground). The Playground is useful to **preview and test your bricks**. It needs no props, but it must be wrapped by the [Admin](/api-reference/components/admin) component to receive the needed context. The route where this component is shown has to be specified in [ReactBricks](/api-reference/components/react-bricks)'s [configuration](/common-tasks/customize-react-bricks/) parameter `playgroundPath`. ## Usage example ```tsx {2,7} import React from 'react' import { Admin, Playground } from 'react-bricks' const PlaygroundPage = () => { return ( ) } export default PlaygroundPage ``` # Preview > Component that renders a shared preview link for draft or unpublished page content. The `` component renders the preview page used by React Bricks preview links. From the Editor, users can generate a preview link for a page and share it with people who are not React Bricks users. The link includes a preview token, allowing the preview page to render that page content even if it is still draft or unpublished. Use `` in the route configured as `previewPath` in your [React Bricks configuration](/common-tasks/customize-react-bricks/). The default preview path is `/preview`. ## Props ```ts interface PreviewProps { renderWrapper?: (args: types.IRenderWrapperArgs) => React.ReactElement } ``` | Property | Definition | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `renderWrapper?` | Optional function to wrap the previewed page content. It receives `children`, the page values and the render environment. See [`IRenderWrapperArgs`](/api-reference/types-reference/interfaces/#irenderwrapperargs). | ## Usage example ```tsx title="pages/preview.tsx" import { Preview } from 'react-bricks/frontend' export default function PreviewPage() { return } ``` ## Usage with renderWrapper Use `renderWrapper` when the preview page needs the same layout wrapper as the public website, or a custom wrapper for preview rendering. ```tsx title="pages/preview.tsx" import { Preview } from 'react-bricks/frontend' export default function PreviewPage() { return ( (
{children}
)} /> ) } ``` ## RSC projects For React Server Components projects, use [`fetchPagePreview`](/rsc/#fetchpagepreview) from `react-bricks/rsc` instead. # ReactBricks > Component that wraps all the other React Bricks components and acts as a Provider for the . The `` component wraps all the other React Bricks components and acts as a Provider for the [``](/api-reference/hooks/use-react-bricks-context) that make the [configuration](/common-tasks/customize-react-bricks) and other information (such as the React Bricks version) available to all the other components. ## Usage example ```tsx import { ReactBricks, types } from 'react-bricks/frontend' {...}} navigate={...} loginPath="/" editorPath="/admin/editor" playgroundPath="/admin/playground" appSettingsPath="/admin/app-settings" previewPath="/preview" getAdminMenu={({ isAdmin }) => {...}} isDarkColorMode={colorMode === 'dark'} toggleColorMode={...} useCssInJs={false} appRootElement="#root" clickToEditSide={types.ClickToEditSide.BottomRight} customFields={...} responsiveBreakpoints={...} enableAutoSave disableSaveIfInvalidProps enablePreview blockIconsPosition={types.BlockIconsPosition.InsideBlock} enablePreviewImage enableUnsplash unsplashApiKey="..." enableDefaultEmbedBrick permissions={{ ... }} > ... ``` # useAdminContext > Read the React Bricks Admin context, including preview mode and current page data. ```ts const useAdminContext = (): types.IReadAdminContext ``` Hook with no arguments to access some useful values from the [AdminContext](#admincontext). It returns an object. ### Example usage ```ts const { isAdmin, previewMode } = useAdminContext() ``` ## AdminContext The `AdminContext` provides the context needed by the admin editing interface. The `useAdminContext` returned object has the following interface ```ts interface IReadAdminContext { isAdmin: boolean previewMode: boolean } ``` - `isAdmin` is `true` in the Admin interface and `false` on the public front-end. - `previewMode` is `true` when the Full-screen preview is active in the Admin interface and `false` otherwise. The [`` component](/api-reference/components/admin) wraps all the children with the AdminContext Provider. # useAuth > Hook that returns two authentication functions to execute the login and logout. Hook with no arguments that returns two **authentication functions** used internally by React Bricks to execute the login and logout. When using React Bricks admin components, there should be **no need to call this from your code**. ### Example usage ```jsx const { loginUser, logoutUser } = useAuth() ``` ## loginUser Function with the following signature: ```jsx const loginUser: (email: string, password: string) => Promise ``` ### Example usage ```tsx const { loginUser } = useAuth() const handleLogin = (event: React.FormEvent) => { event.preventDefault() loginUser(email, password).then( () => navigate(editorPath), (error) => { setError(error) } ) } ``` ## logoutUser Function with the following signature: ```tsx const logoutUser: () => void ``` ### Example usage ```jsx const { logoutUser } = useAuth() return ``` # usePagePublic > Hook that lets you easily retrieve the content of a page from React Bricks' APIs. The `usePagePublic` hook lets you easily **retrieve the content of a page** from React Bricks' APIs. ## Signature ```ts const usePagePublic = ( slug: string, language?: string ): types.IQueryResult ``` ## Usage example See [PageViewer example with usePage](/api-reference/components/page-viewer#usage-example-with-usepage-hook) # usePageValues > Read page metadata and custom values from inside a React Bricks brick. The `usePageValues` hook allows you to access and modify page meta values within your bricks. ## Usage Example ```tsx // The returned array contains the Page values and a setter function const [page, setPage] = usePageValues() return (
{/* Access the page creation date */}

Created at {moment(page.createdAt).format('MM/DD/YYYY')}.

{/* Access the page title */}

Page title: {page.meta.title}

{/* Access a custom field's value */}

Page title: {page.customValues.productId}

) ``` ## Hook Signature ```ts const usePageValues = (): [ types.PageValues, (pageData: types.PartialPage) => void ] ``` The `usePageValues` is called without arguments. It returns an array containing the page values and a setter function: `[pageValues, setPageValues]`. - `pageValues` is an object with the structure shown below - `setPageValues` is a function to set the values (merging the object one level deep). :::note On the frontend site, the `setPage` function has no effect. ::: ## Returned Values The returned object has the following structure: ```ts type PageValues = { id: string type: string name: string slug: string variantName: string variantWeight: number meta: IMeta customValues?: Props externalData?: Props emailMarketingConfig?: EmailMarketingConfig authorId?: string author: Author invalidBlocksTypes?: string[] status: PageStatus editStatus: EditStatus isLocked: boolean tags: string[] category?: string createdAt: string publishedAt?: string scheduledForPublishingOn?: string scheduledForUnpublishingOn?: string language: string translations: Translation[] variants: Variant[] lastEditedBy: LastEditedBy app?: AppOnPage } ``` For more details, refer to the following type definitions: - [Page](/api-reference/types-reference/types#page) - [IMeta](/api-reference/types-reference/interfaces#imeta) - [Props](/api-reference/types-reference/types/#props) - [Author](/api-reference/types-reference/types/#author) - [PageStatus](/api-reference/types-reference/enums/#pagestatus) - [EditStatus](/api-reference/types-reference/enums/#editstatus) - [Translation](/api-reference/types-reference/types/#translation) - [LastEditedBy](/api-reference/types-reference/types/#lasteditedby) # usePagesPublic > Fetch published React Bricks pages from the public API in frontend components. **Hook to fetch the list of published pages.** It won't return pages with status "DRAFT". ## Arguments The `usePagesPublic` hook accepts an optional configuration object with the following props: ```ts { type?: string types?: string[] tag?: string language?: string usePagination?: boolean page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any} } ``` | Property | Definition | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | Optional string to return only the pages with the specified page type. | | `types` | Optional array of strings to return only the pages with one of the specified page types. | | `tag` | Optional string to return only the pages with the specified tag. | | `language` | Optional language for the page. If not specified, the default language will be used. | | `usePagination` | If true, it will consider the page and pageSize parameters and it will return paginated results | | `page` | The page number, in case of pagination | | `pageSize` | The page size, in case of pagination | | `sort` | Sort parameter: currently it accepts only `createdAt`,`-createdAt`,`publishedAt`,`-publishedAt` | | `filterBy` | Used to filter by a custom field. The object should have a key for each field and the value that it should have (or an array of possible values). The queries on the fields are in logical AND. For example: `{ category: 'shoes', subcategory: ['snickers', 'running'] }`. At the moment you cannot filter using a complex type (like an object) for the value, so really now it should be `string` or `string[]` } | ## Return value The hook returns an object with `{ data, error, isFetching }` and other properties. `data` contains: - When `usePagination` is `false`, an array of type [PageFromList](/api-reference/types-reference/types#pagefromlist) - When `usePagination` is `true`, an object of type [PagesFromListWithPagination](/api-reference/types-reference/types#pagefromlistwithpagination) ## Usage example ```tsx import { usePagesPublic } from 'react-bricks/frontend' export function ProductGrid() { const { data, error, isFetching } = usePagesPublic({ type: 'product', filterBy: { category: 'shoes', featured: 'true', }, sort: '-publishedAt', usePagination: true, page: 1, pageSize: 12, }) if (isFetching) { return

Loading...

} if (error || !data) { return

Unable to load products.

} const products = 'items' in data ? data.items : data return (
{products.map((product) => (
{product.name}
))}
) } ``` :::tip[Practical how-to] For a broader comparison between ``, `usePagesPublic`, and `fetchPages`, see [List pages by type](https://www.reactbricks.com/how-tos/page-types/list-pages-by-type). ::: # useReactBricksContext > Read React Bricks configuration and runtime values from the React context. ```ts const useReactBricksContext = (): types.IReactBricksContext ``` Hook with no arguments to access the values in [ReactBricksContext](#reactbrickscontext). It returns an object. The values in the returned object are from the configuration you provided to the ReactBricks component, so you should have them available in your project, but this hook could be useful to access them from any component wrapped by ReactBricks, for example a content block. ### Example usage ```ts const { bricks } = useReactBricksContext() ``` ## ReactBricksContext The `ReactBricksContext` provides configuration context to all the children components. It has the following TypeScript interface: ```ts interface IReactBricksContext { version: string appId: string apiKey: string bricks: Bricks themes: types.Theme[] pageTypes: IPageType[] logo: string loginUI: LoginUI contentClassName: string defaultTheme: string renderLocalLink: RenderLocalLink navigate: (path: string) => void loginPath: string editorPath: string mediaLibraryPath: string playgroundPath: string appSettingsPath: string previewPath: string getAdminMenu?: (args: { isAdmin: boolean }) => IMenuItem[] isDarkColorMode?: boolean toggleColorMode?: () => void useCssInJs?: boolean appRootElement: string | HTMLElement clickToEditSide?: ClickToEditSide customFields?: Array responsiveBreakpoints: ResponsiveBreakpoint[] enableAutoSave: boolean disableSaveIfInvalidProps: boolean enablePreview: boolean browserSupport: { webP: boolean; lazyLoading: boolean } blockIconsPosition: BlockIconsPosition enablePreviewImage: boolean enablePreviewIcon: boolean enableUnsplash: boolean unsplashApiKey?: string enableDefaultEmbedBrick: boolean checkUnsavedChanges: boolean permissions?: Permissions allowAccentsInSlugs: boolean warningIfLowBattery: boolean isRtlLanguage: ({ language }: { language: string }) => boolean rtlLanguages: string[] apiPrefix?: string } ``` The [`` component](/api-reference/components/react-bricks) wraps all the children with the ReactBricksContext Provider. # useTagsPublic > Hook that lets you easily retrieve all the Tags from React Bricks' APIs. The `useTagsPublic` hook lets you easily **retrieve all the Tags** from React Bricks' APIs. ## Signature ```ts const useTagsPublic: ( page?: number, pageSize?: number ) => types.IQueryResult<{ items: string[] pagination: { page: number pageSize: number totalItems: number totalPages: number } }> ``` ## Usage example ```tsx {5} import React from 'react' import { useTagsPublic } from 'react-bricks/frontend' const MyBrick: types.Brick = () => { const { data } = useTagsPublic() return (
{data?.items?.map((t) => ( {t} ))}
) } MyBrick.schema = { name: 'my-brick', ... } export default MyBrick ``` # useVisualEdit > Build a custom visual editing component with React Bricks editing state. # Custom Visual editing components Sometimes you may want to add new visual editing components beyond the predefined Text, RichText, Image, or File. For instance, you might want to create a code editor (like the one found in React Bricks UI blocks) or a canvas where editors can draw. The `useVisualEdit` hook allows you to create a custom visual editing component that reads from a block property and saves back to that property. ## Usage Example ```jsx const [value, setValue, isReadOnly] = useVisualEdit('my-prop') if (isReadOnly) { // Here we are on the frontend return (
{value}
) } // Here we are in the content administration interface return ( ) ``` ## Hook Definition ```ts const useVisualEdit = ( propName: string ): [any, (value: any) => void, boolean] ``` The `useVisualEdit` hook takes a propName as argument and returns a `[value, setValue, isReadOnly]` array. You can use `value`, `setValue`, and `isReadOnly` to create your editing component: - `value` is the value of the prop - `setValue` function that accepts a value as argument and sets the prop accordingly - `isReadOnly` is true in the frontend and Preview mode, while false in the Admin Editor # API Docs Introduction > Overview of the React Bricks API reference for components, hooks, utilities, and types. While the Documentation section was targeted at developers leveraging the starter projects, this **advanced section** is useful to developers who are creating their own architecture using React Bricks, or who need to **fully understand how React Bricks components work**. This section explains all the components, context, hooks and utilities exported by the [`react-bricks`](https://www.npmjs.com/package/react-bricks) library. **This section is organized by type** of exported entity and serves as a reference that you might reach from the search bar. So, red pill and I show you how deep the rabbit hole goes... 🐇 # Components structure > Learn everything you need to know about the components structure. ## ReactBricks The [``](/api-reference/components/react-bricks) component wraps everything and it acts as a **Provider** for the [``](/api-reference/hooks/use-react-bricks-context) that make the configuration available through Context to all the other components. ## Frontend site ![components-structure-frontend](/images/components-structure-frontend.svg) The frontend website uses the [``](/api-reference/components/page-viewer) component to **render a page**. It has a `page` prop which expects the content of a [Page](/basics/pages-and-page-types) from React Bricks API (see also [`usePage`](/api-reference/hooks/use-page-public) and [`fetchPage`](/api-reference/utilities/fetch-page)). It renders your bricks with React Bricks visual edit components (Text, RichText, Image, File, Repeater) in read-only mode. **Images** are lazy loaded and an optimized version is requested based on screen resolution. The **Repeater** components render your nested block as they do in the Admin interface. If you are logged in the Admin, the PageViewer components renders also a **floating edit button**, so that you can directly go to the interface to edit the page you are viewing. ## Admin ![components-structure-frontend](/images/components-structure-admin.svg) On the Admin, every component should be wrapped also by the [``](/api-reference/components/admin) component, which manages **authentication** and renders the Interface **menu**. The [``](/api-reference/components/admin) component contains also a **Provider** for the [`AdminContext`](/api-reference/hooks/use-admin-context) (current page, preview mode, etc.). If you build the admin interface yourself, you should create **views** (routed by your router) for the login, editor, playground and page settings pages. Each of these views will have the wrapping [``](/api-reference/components/admin) component and the view-related component: [``](/api-reference/components/login), [``](/api-reference/components/editor), [``](/api-reference/components/playground), [``](/api-reference/components/app-settings) # Enums > Reference for the main React Bricks exported enums used in configuration and content editing. ## SideEditPropType ```ts enum SideEditPropType { Text = 'TEXT', Textarea = 'TEXTAREA', Number = 'NUMBER', Date = 'DATE', Range = 'RANGE', Boolean = 'BOOLEAN', Select = 'SELECT', Autocomplete = 'AUTOCOMPLETE', Image = 'IMAGE', Custom = 'CUSTOM', Relationship = 'RELATIONSHIP', IconSelector = 'ICON-SELECTOR', } ``` ## OptionsDisplay ```ts enum OptionsDisplay { Select = 'SELECT', Radio = 'RADIO', Color = 'COLOR', } ``` ## RichTextFeatures ```ts enum RichTextFeatures { Bold = 'BOLD', Italic = 'ITALIC', Code = 'CODE', Highlight = 'HIGHLIGHT', Subscript = 'SUB', Superscript = 'SUP', Link = 'LINK', UnorderedList = 'UL', OrderedList = 'OL', Heading1 = 'H1', Heading2 = 'H2', Heading3 = 'H3', Heading4 = 'H4', Heading5 = 'H5', Heading6 = 'H6', Quote = 'QUOTE', } ``` ## IconSets ```ts enum IconSets { Lucide = 'lu', HeroIconSolid = 'hi-solid', HeroIconOutline = 'hi-outline', FontAwesome = 'fa6', Feather = 'fi', } ``` ## PageStatus ```ts export enum PageStatus { Draft = 'DRAFT', Published = 'PUBLISHED', } ``` ## EditStatus ```ts enum EditStatus { Merged = 'MERGED', Working = 'WORKING', MergeRequested = 'MERGE_REQUESTED', } ``` ## PlaygroundSelectedItemType ```ts export enum PlaygroundSelectedItemType { Block = 'BLOCK', PageType = 'PAGE-TYPE', } ``` ## DeviceType ```ts enum DeviceType { Desktop = 'DESKTOP', Tablet = 'TABLET', Phone = 'PHONE', } ``` ## ClickToEditSide ```ts enum ClickToEditSide { BottomRight = 'BOTTOM-RIGHT', BottomLeft = 'BOTTOM-LEFT', TopRight = 'TOP-RIGHT', TopLeft = 'TOP-LEFT', None = 'NONE', } ``` ## BlockIconsPosition ```ts enum BlockIconsPosition { InsideBlock = 'INSIDE-BLOCK', OutsideBlock = 'OUTSIDE-BLOCK', } ``` # Interfaces > Reference for the main React Bricks exported interfaces used by components, configuration, and API data. ## FetchPagesType ```ts interface FetchPagesType { ( apiKey: string, { type, types, tag, language, page, pageSize, sort, filterBy, usePagination, }: { type?: string types?: string[] tag?: string language?: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } usePagination: T } ): Promise ( apiKey: string, { type, types, tag, language, page, pageSize, sort, filterBy, }: { type?: string types?: string[] tag?: string language?: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } } ): Promise (apiKey: string): Promise } ``` ## IBlockType ```ts interface IBlockType { name: string label: string description?: string getDefaultProps?: () => Partial hideFromAddMenu?: boolean disabled?: boolean disabledIcon?: 'purchase' | 'maintenance' disabledLink?: string disabledTooltip?: string sideEditProps?: Array | ISideGroup> repeaterItems?: IRepeaterItem[] newItemMenuOpen?: boolean groupByRepeater?: boolean mapExternalDataToProps?: (externalData: Props, brickProps?: T) => Partial getExternalData?: ( page: Page, brickProps?: T, args?: any ) => Promise> playgroundLinkUrl?: string playgroundLinkLabel?: string theme?: string category?: string tags?: string[] previewImageUrl?: string previewIcon?: React.ReactElement stories?: BrickStory>[] astroInteractivity?: | 'load' | { load: true } | 'idle' | { idle: true } | { idle: { timeout: number } } | 'visible' | { visible: true } | { visible: { rootMargin: string } } | { media: string } | { only: string } } ``` ## IBrickStory ```ts interface IBrickStory { brickName: string storyName: string locked?: boolean canAddAfter?: boolean canAddBefore?: boolean } ``` ## ICategory ```ts interface ICategory { category?: string } ``` ## ICleanBlocks ```ts interface ICleanBlocks { blocks: IContentBlock[] invalidBlocksTypes: string[] } ``` ## IColor ```ts interface IColor { color: string [propName: string]: any } ``` ## IContentBlock ```ts interface IContentBlock { id: string type: string props: Props locked?: boolean canAddAfter?: boolean canAddBefore?: boolean canEditContent?: boolean } ``` ## ICustomKnobProps ```ts interface ICustomKnobProps { id: string value: any onChange: any isValid: boolean errorMessage?: string } ``` ## IFileSource ```ts interface IFileSource { name: string url: string size: number extension: string pagesNum: number title?: string | undefined alt?: string | undefined copyright?: string | undefined source?: string | undefined } ``` ## IImageSource ```ts interface IImageSource { src: string srcSet?: string type?: string fallbackSrc?: string fallbackSrcSet?: string fallbackType?: string placeholderSrc?: string alt?: string seoName?: string width?: number height?: number highPriority?: boolean hashId?: string crop?: ICrop transform?: ITransform } ``` ## ITransform ```ts interface ITransform { rotate?: number flip?: { horizontal: boolean vertical: boolean } } ``` ## ICrop ```ts interface ICrop { x: number y: number width: number height: number } ``` ## IMenuItem ```ts interface IMenuItem { label: string path?: string } ``` ## IMeta ```ts interface IMeta extends MetaData { language?: string openGraph?: OpenGraphData twitterCard?: TwitterCardData schemaOrg?: SchemaOrgData } ``` ## IOption ```ts interface IOption { value: T label: string disabled?: boolean disabledTooltip?: string [otherProps: string]: unknown } ``` ## IPageType ```ts interface IPageType { name: string pluralName: string isEntity?: boolean isEmailMarketing?: boolean headlessView?: boolean allowedBlockTypes?: string[] excludedBlockTypes?: string[] defaultLocked?: boolean defaultStatus?: PageStatus defaultFeaturedImage?: string getDefaultContent?: () => (string | IBrickStory | IContentBlock)[] customFields?: Array getExternalData?: (page: Page, args?: any) => Promise getDefaultMeta?: (page: PageFromList, externalData: Props) => Partial metaImageAspectRatio?: number categories?: ICategory[] slugPrefix?: ISlugPrefix template?: Array renderWrapper?: (args: IRenderWrapperArgs) => React.ReactElement renderEmailHtml?: (args: { children: React.ReactElement page: PageValues }) => string | Promise } ``` ## IRenderWrapperArgs ```ts interface IRenderWrapperArgs { children: React.ReactElement page: PageValues renderEnvironment: RenderEnvironment } ``` ## IReactBricksContext ```ts interface IReactBricksContext { version: string appId: string apiKey: string apiPrefix?: string environment?: string bricks: Bricks themes: types.Theme[] pageTypes: IPageType[] logo: string loginUI: LoginUI contentClassName: string defaultTheme: string renderLocalLink: RenderLocalLink navigate: (path: string) => void loginPath: string editorPath: string mediaLibraryPath: string playgroundPath: string appSettingsPath: string previewPath: string getAdminMenu?: (args: { isAdmin: boolean }) => IMenuItem[] isDarkColorMode?: boolean toggleColorMode?: () => void useCssInJs?: boolean appRootElement: string | HTMLElement clickToEditSide?: ClickToEditSide customFields?: Array responsiveBreakpoints: ResponsiveBreakpoint[] enableAutoSave: boolean disableSaveIfInvalidProps: boolean enablePreview: boolean browserSupport: { webP: boolean; lazyLoading: boolean } blockIconsPosition: BlockIconsPosition enablePreviewImage: boolean enablePreviewIcon: boolean enableUnsplash: boolean unsplashApiKey?: string enableDefaultEmbedBrick: boolean checkUnsavedChanges: boolean permissions?: Permissions allowAccentsInSlugs: boolean warningIfLowBattery: boolean isRtlLanguage: ({ language }: { language: string }) => boolean rtlLanguages: string[] } ``` ## IReadAdminContext ```ts interface IReadAdminContext { isAdmin: boolean previewMode: boolean currentPage: ICurrentPage showRichTextModal: ShowRichTextModal } ``` ## IRepeaterItem ```ts interface IRepeaterItem { name: string label?: string itemType?: string itemLabel?: string defaultOpen?: boolean min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean items?: { type: string label?: string min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean }[] } ``` ## ISideEditProp ```ts interface ISideEditPropPage { name: string label: string type: SideEditPropType component?: React.FC validate?: (value: any, props?: T) => boolean | string show?: (props: T, page?: Page, user?: User) => boolean helperText?: string textareaOptions?: { height?: number } imageOptions?: { maxWidth?: number quality?: number aspectRatio?: number } rangeOptions?: { min?: number max?: number step?: number } selectOptions?: { options?: IOption[] getOptions?: (props: Props) => IOption[] | Promise display: OptionsDisplay } autocompleteOptions?: { placeholder?: string getOptions: (input: string, props: Props) => any[] | Promise getKey: (option: any) => string | number getLabel: (option: any) => string renderOption?: ({ option, selected, focus, }: { option: any selected: boolean focus: boolean }) => React.ReactElement debounceTime?: number getNoOptionsMessage?: (input?: string) => string } iconSelectorOptions?: { iconSets?: IconSets[] } relationshipOptions?: { label?: string references: string multiple: boolean embedValues?: boolean } onChange?: (props: T) => Partial } interface ISideEditProp extends ISideEditPropPage { shouldRefreshText?: boolean shouldRefreshStyles?: boolean } ``` ## ISideGroup ```ts interface ISideGroup { groupName: string defaultOpen?: boolean show?: (props: T, page?: Page, user?: User) => boolean props: ISideEditProp[] | ISideEditPropPage[] } ``` ## LoginUI ```ts interface LoginUI { sideImage?: string logo?: string logoWidth?: number logoHeight?: number welcomeText?: string welcomeTextStyle?: React.CSSProperties } ``` ## ReactBricksConfig ```ts interface ReactBricksConfig { appId: string apiKey: string apiPrefix?: string environment?: string bricks?: types.Brick[] | types.Theme[] pageTypes?: types.IPageType[] logo?: string loginUI?: LoginUI contentClassName?: string defaultTheme?: string renderLocalLink: types.RenderLocalLink navigate: (path: string) => void loginPath?: string editorPath?: string mediaLibraryPath?: string playgroundPath?: string appSettingsPath?: string previewPath?: string getAdminMenu?: (args: { isAdmin: boolean }) => IMenuItem[] isDarkColorMode?: boolean toggleColorMode?: () => void useCssInJs?: boolean appRootElement: string | HTMLElement clickToEditSide?: ClickToEditSide customFields?: Array responsiveBreakpoints?: ResponsiveBreakpoint[] enableAutoSave?: boolean disableSaveIfInvalidProps?: boolean enablePreview?: boolean blockIconsPosition?: BlockIconsPosition enablePreviewImage?: boolean enablePreviewIcon?: boolean enableUnsplash?: boolean unsplashApiKey?: string enableDefaultEmbedBrick?: boolean checkUnsavedChanges?: boolean permissions?: Permissions allowAccentsInSlugs?: boolean warningIfLowBattery?: boolean rtlLanguages?: Array } ``` ## ResponsiveBreakpoint ```ts interface ResponsiveBreakpoint { type: DeviceType width: number | string label: string } ``` ## UsePagesType ```ts interface UsePagesType { ({ type, types, tag, language, page, pageSize, sort, filterBy, usePagination, }: { type?: string types?: string[] tag?: string language: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } usePagination: T }): UseQueryResult< T extends true ? types.PagesFromListWithPagination : types.PageFromList[], unknown > ({ type, types, tag, language, page, pageSize, sort, filterBy, }: { type?: string types?: string[] language: string tag?: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } }): UseQueryResult (): UseQueryResult } ``` ## UsePagesPublicType ```ts interface UsePagesPublicType { ({ type, types, tag, language, page, pageSize, sort, filterBy, usePagination, }: { type?: string types?: string[] tag?: string language?: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } usePagination: T }): UseQueryResult< T extends true ? types.PagesFromListWithPagination : types.PageFromList[], unknown > ({ type, types, tag, language, page, pageSize, sort, filterBy, }: { type?: string types?: string[] tag?: string language?: string page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any } }): UseQueryResult (): UseQueryResult } ``` # Types > Reference for the main React Bricks exported TypeScript types. ## Author ```ts type Author = { id: string email: string firstName: string lastName: string avatarUrl?: string company?: string } ``` ## BlockPluginConstructor ```ts type BlockPluginConstructor = (blockPlugin: BlockPlugin) => RichTextPlugin ``` ## Brick ```ts type Brick = React.FC & { schema: IBlockType } ``` ## Bricks ```ts type Bricks = { [key: string]: Brick } ``` ## BrickStory ```ts type BrickStory = { id: string name: string showAsBrick?: boolean previewImageUrl?: string disabled?: boolean disabledIcon?: 'purchase' | 'maintenance' disabledLink?: string disabledTooltip?: string props: T } ``` ## Category ```ts type Category = { categoryName: string bricks: Brick[] } ``` ## CustomRole ```ts type CustomRole = { id: string name: string } ``` ## EditingUser ```ts type EditingUser = { id: string email: string firstName: string lastName: string company: string avatarUrl?: string } ``` ## Icon ```ts type Icon = { name: string svg: string url: string set: IconSets } ``` ## Language ```ts type Language = { code: string name: string } ``` ## LastEditedBy ```ts type LastEditedBy = { date: string user: EditingUser } ``` ## MarkPluginConstructor ```ts type MarkPluginConstructor = (markPlugin: MarkPlugin) => RichTextPlugin ``` ## Page ```ts type Page = { id: string type: string name: string slug: string variantName: string variantWeight: number meta: IMeta customValues?: Props externalData?: Props emailMarketingConfig?: EmailMarketingConfig content: IContentBlock[] workingContent?: IContentBlock[] committedContent?: IContentBlock[] authorId?: string author: Author invalidBlocksTypes?: string[] status: PageStatus editStatus: EditStatus isLocked: boolean tags: string[] category?: string createdAt: string publishedAt?: string scheduledForPublishingOn?: string scheduledForUnpublishingOn?: string language: string translations: Translation[] variants: Variant[] lastEditedBy: LastEditedBy app?: AppOnPage } ``` ## PageFromList ```ts type PageFromList = Omit ``` ## PageFromListWithPagination ```ts export type PagesFromListWithPagination = { items: PageFromList[] pagination: { page: number pageSize: number totalItems: number totalPages: number } } ``` ## PageValues ```ts type PageValues = Omit ``` ## RenderEnvironment ```ts type RenderEnvironment = 'Frontend' | 'Preview' | 'Admin' | 'Email' ``` ## PartialPage ```ts type PartialPage = Partial ``` ## Permissions ```ts type Permissions = { canAddPage?: (user: PermissionUser, pageType: string) => boolean canAddTranslation?: ( user: PermissionUser, pageType: string, language: string ) => boolean canSeePageType?: (user: PermissionUser, pageType: string) => boolean canSeePage?: ( user: PermissionUser, page: Omit ) => boolean canEditPage?: (user: PermissionUser, page: PermissionPage) => boolean canDeletePage?: ( user: PermissionUser, page: Omit ) => boolean canDeleteTranslation?: (user: PermissionUser, page: PermissionPage) => boolean canUseBrick?: (user: PermissionUser, brick: PermissionBrick) => boolean } ``` ## PermissionBrick ```ts type PermissionBrick = { name: string category: string theme: string tags: string[] } ``` ## PermissionPage ```ts type PermissionPage = { slug: string pageType: string language: string } ``` ## PermissionUser ```ts type PermissionUser = { firstName: string lastName: string email: string isAdmin: boolean role: string customRole?: CustomRole } ``` ## Props ```ts type Props = { [key: string]: any } ``` ## RenderLocalLink ```ts type RenderLocalLink = ({ href, target, className, activeClassName, isAdmin, tabIndex, children, }: React.PropsWithChildren<{ href: string target?: string className?: string activeClassName?: string isAdmin?: boolean tabIndex?: number }>) => React.ReactElement ``` ## RepeaterItems ```ts type RepeaterItemDefault = IContentBlock | Omit | Props type RepeaterItems = Array ``` ## Translation ```ts type Translation = { language: string slug: string name: string status: PageStatus editStatus: EditStatus isLocked: boolean scheduledForPublishingOn: string } ``` ## Theme ```ts type Theme = { themeName: string bannerText?: string bannerLink?: string categories: Category[] } ``` ## TemplateSlot ```ts type TemplateSlot = { slotName: string label: string min?: number max?: number allowedBlockTypes?: string[] excludedBlockTypes?: string[] editable?: boolean getDefaultContent?: () => (string | IBrickStory | IContentBlock)[] } ``` ## User ```ts type User = { id: string email: string firstName: string lastName: string company: string avatarUrl?: string isAdmin: boolean token: string appName: string appId: string appEnv: string deployHookUrl?: string deployHookMethod?: string deployHookTriggerOnScheduledPublishing: boolean deployHookStagingUrl?: string deployHookStagingMethod?: string deployHookStagingTriggerOnScheduledPublishing: boolean deployHookDevUrl?: string deployHookDevMethod?: string deployHookDevTriggerOnScheduledPublishing: boolean eventsHookUrl?: string eventsHookAuthToken?: string canCreatePage: boolean canDeletePage: boolean canDeploy: boolean canDeployStaging: boolean canDeployDev: boolean canEditPageAttributes: boolean // add to dashboard canEditSeo: boolean // add to dashboard canApprove: boolean // add to dashboard role: string customRole?: CustomRole plan: string isVerified: boolean languages: Language[] defaultLanguage: string hostname: string useWorkingCopy: boolean useApprovalWorkflow: boolean subscription: { maxStories: number collaboration: boolean deployHookStaging: boolean deployHookDev: boolean scheduledPublishing: boolean abTesting: boolean embedPages: boolean lockBlocks: boolean flexibleRoles: boolean advancedSeo: boolean eventsLog: boolean maxFileSize: number maxImageSize: number maxFilesBatch: number maxFilesConcurrency: number diskSpace: number advancedDam: boolean workingCopy: boolean approvalWorkflow: boolean template: boolean externalData: boolean richTextExt: boolean aiText: boolean aiGen: boolean aiSeo: boolean emailMarketing: boolean forms: boolean } emailMarketingConfig?: { providers: Array<{ value: string; label: string }> testRecipients: string[] } } | null ``` # blockPluginConstructor > Create a custom RichTextExt block plugin with the blockPluginConstructor helper. As we saw, the [RichTextExt](/api-reference/visual-components/rich-text-ext) can be extended using a plugin system. For a typical Block or List plugin (heading, quote, unordered list...), React Bricks provides the `blockPluginConstructor` helper that allows you to create a new plugin very quickly. It just accepts a simple `BlockPlugin` object: ```ts type BlockPluginConstructor = (blockPlugin: BlockPlugin) => RichTextPlugin interface BlockPlugin { name: string isInline?: boolean itemName?: string label?: string hotKey?: string render: (props: RenderElementProps) => React.ReactElement renderItem?: (props: RenderElementProps) => React.ReactElement icon?: React.ReactElement } ``` For the meaning of the arguments, you can see the interface for a [`RichTextPlugin`](/api-reference/visual-components/rich-text-ext). The `icon` is the button's icon. If you set an `itemName` React Bricks will create a List plugin, otherwise a Block one. ## Usage example Here's the code for React Bricks `h1` plugin, created using the `blockPluginConstructor` ```tsx import React from 'react' import { MdLooksOne } from 'react-icons/md' import { blockPluginConstructor } from 'react-bricks/frontend' const plugin = blockPluginConstructor({ name: 'h1', hotKey: 'mod+shift+1', render: (props: any) =>

{props.children}

, icon: , }) export default plugin ``` # blockWithModalPluginConstructor > Plugin helper to create a Block plugin with a configuration modal interface. As we saw, the [RichTextExt](/api-reference/visual-components/rich-text-ext) can be extended using a plugin system. The `blockPluginConstructor` helper is meant to create an advanced plugin, which needs parameters configured through a modal interface. It accepts a `BlockWithModalPlugin` object: ```ts type BlockPluginConstructor = ( blockPlugin: BlockWithModalPlugin ) => RichTextPlugin type BlockWithModalPlugin = BlockPlugin & { name: string isInline?: boolean itemName?: string label?: string hotKey?: string render: (props: RenderElementProps) => React.ReactElement renderItem?: (props: RenderElementProps) => React.ReactElement icon?: React.ReactElement // highlight-next-line pluginCustomFields: Array // highlight-next-line getDefaultProps?: () => Props // highlight-next-line renderAdmin?: (props: RenderElementProps) => React.ReactElement // highlight-next-line renderItemAdmin?: (props: RenderElementProps) => React.ReactElement } ``` As you can see, it's like a [BlockPlugin](/api-reference/utilities/block-plugin-constructor), but for the highlighted props: - `pluginCustomFields`: the array of custom fields the plugin needs. The interface is the same used for sidebar controls of a brick. See [SideEditProps](/bricks/schema/side-edit-props). - `getDefaultProps`: function that returns the default values for the custom fields. - `renderAdmin`: what should be rendered on the Admin interface (sometimes it may be useful to render something different from the frontend in the Admin interface) - `renderItemAdmin`: the `renderItem` function to render an item on the Admin interface. ## Usage example Here's the code for a custom "stock quote" plugin, created using the `blockPluginConstructor`: ```tsx import React from 'react' import { MdLooksOne } from 'react-icons/md' import { blockPluginConstructor } from 'react-bricks/frontend' // or 'react-bricks/rsc const plugin = blockWithModalPluginConstructor({ name: 'stockQuote', label: 'Stock quote', isInline: true, hotKey: 'mod+k', icon: , render: (props) => ( {props.children} {renderStockData(props.element?.data)} // renderStockData renders the stock value, not relevant here ), renderAdmin: (props) => ( {props.children || 'STOCK'} {renderStockData(props.element?.data)} ), getDefaultProps: () => { return { stockCode: {}, type: 'c', } }, pluginCustomFields: [ { name: 'stockCode', label: 'Stock code', type: types.SideEditPropType.Autocomplete, autocompleteOptions: { getOptions: async (input) => { if (!input) { return [] } return fetch( `https://finnhub.io/api/v1/search?q=${input}&token=cmpac5hr01qg7bbo20r0cmpac5hr01qg7bbo20rg`, { next: { revalidate: 10, }, } ) .then((res) => res.json()) .then((data) => data.result) }, getKey: (option) => option?.symbol, getLabel: (option) => option?.displaySymbol ? `${option?.description} (${option?.displaySymbol})` : '', getNoOptionsMessage: (input) => `No stocks for "${input}"`, debounceTime: 200, }, }, { name: 'type', label: 'Data Type', type: types.SideEditPropType.Select, selectOptions: { display: types.OptionsDisplay.Select, options: [ { label: 'Value', value: 'c' }, { label: 'Daily change', value: 'd' }, { label: 'Daily change %', value: 'dp' }, ], }, }, ], }) export default plugin ``` # cleanPage > Function that prepares the page content retrieved by React Bricks APIs to be used in the PageViewer component. The cleanPage function prepares the page content retrieved by React Bricks APIs to be used in the [`PageViewer`](/api-reference/components/page-viewer) component. It **removes all the invalid blocks** (unknown in the schema or not allowed for this page type). ## Signature ```ts const cleanPage = ( page: types.Page, pageTypes: types.IPageType[], bricks: types.Bricks ): types.Page ``` | Property | Definition | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `page` | The page object, of type [`Page`](/api-reference/types-reference/types/#page). | | `pageTypes` | The pageType schema, of type [`IPageType[]`](/api-reference/types-reference/interfaces#ipagetype), as [defined here](/page-types). | | `bricks` | The block's schema, of type [`IBlockType[]`](/api-reference/types-reference/interfaces#iblocktype), as [defined here](/bricks/schema). | ## Return value `cleanPage` returns an object of type [`Page`](/api-reference/types-reference/types/#page), with the clean content and the `invalidBlocksTypes` array containing the name of each invalid block that was removed. ## Usage example ```ts {2} fetchPage('about-us', 'API_KEY').then((data) => { const myPage = cleanPage(data, pageTypes, bricks) console.log(myPage.content) }) ``` # createAbTestingMiddleware > Middleware helper to resolve React Bricks A/B Testing variants in Next.js Pages and Astro projects. `createAbTestingMiddleware` is a middleware helper for projects using React Bricks A/B Testing. Use it in: - Next.js Pages projects - Astro projects It resolves the active A/B Testing variant for a request, so your application can render the correct page variant and track analytics consistently. The selected variant is stored in a cookie. When rendering the page, read it with [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) and pass it to [`fetchPage`](/api-reference/utilities/fetch-page/) as `variantName`. ## When to use it Use `createAbTestingMiddleware` when your project uses [A/B Testing and Multischeduling](/cms-features/ab-testing-multischeduling/) and does not need to chain the A/B Testing middleware with the Next.js App i18n middleware. For Next.js App projects that need to chain with i18n, use [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/). ## Implementation notes The exact middleware file and request/response types depend on your framework. Use the starter implementation for your framework as the recommended reference: [https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps](https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps) ## Related docs - [Implement A/B Testing](/common-tasks/implement-ab-testing/) - [A/B Testing and Multischeduling](/cms-features/ab-testing-multischeduling/) - [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) # createI18nMiddleware > Middleware helper to make i18n routing easier to manage in Next.js App and Astro projects. `createI18nMiddleware` is a middleware helper for React Bricks projects with localized routes. Use it in: - Next.js App projects - Astro projects It makes i18n routing easier to manage by centralizing locale resolution in middleware. ## When to use it Use `createI18nMiddleware` when your project has localized content and needs routing middleware to resolve the correct language before rendering. If the same project also uses A/B Testing in Next.js App, use [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) to chain i18n and A/B Testing concerns. ## Related docs - [Localization](/common-tasks/localization/) - [Localization CMS feature](/cms-features/localization/) - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) # createWithAbTestingMiddleware > Middleware helper to chain React Bricks A/B Testing with i18n middleware in Next.js App projects. `createWithAbTestingMiddleware` is a middleware helper for Next.js App projects where A/B Testing must be chained with i18n routing. It lets one request flow resolve both: - the active locale - the active A/B Testing variant The selected variant is stored in a cookie. When rendering the page, read it with [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) and pass it to [`fetchPage`](/api-reference/utilities/fetch-page/) as `variantName`. ## When to use it Use `createWithAbTestingMiddleware` when: - your project uses the Next.js App Router - your project uses React Bricks i18n middleware - your project also uses [A/B Testing and Multischeduling](/cms-features/ab-testing-multischeduling/) For Next.js Pages or Astro projects, use [`createAbTestingMiddleware`](/api-reference/utilities/create-ab-testing-middleware/). ## Implementation notes Middleware chaining is project-specific, because it depends on your routing, locales, and analytics setup. Use the starter implementation as the recommended reference: [https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps/nextjs-app](https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps/nextjs-app) ## Related docs - [Implement A/B Testing](/common-tasks/implement-ab-testing/) - [Localization](/common-tasks/localization/) - [`createI18nMiddleware`](/api-reference/utilities/create-i18n-middleware/) - [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) # fetchPage > Function to retrieve the content of one page from outside the React context. The fetchPage function is useful when you want to **retrieve the content of one page from outside the React context** (where you could use the [usePagePublic hook](/api-reference/hooks/use-page-public) instead). In particular, this comes in handy during the build process of a static website. This is the method used in React Bricks starter projects to retrieve page content outside React. ## Signature ```ts const fetchPage = async ({ slug, language, variantName, config, fetchOptions, }: { slug: string language?: string variantName?: string config: types.ReactBricksConfig fetchOptions?: types.FetchOptions }): Promise ``` | Property | Definition | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `slug` | The slug of the page to fetch. Use `/` for the home page. | | `language?` | The language of the desired translation for the page, if more than one page shares the same slug. | | `variantName?` | The A/B Testing variant name to fetch. Use it with [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) to keep the served variant stable. | | `config` | The React Bricks configuration object. | | `fetchOptions?` | Fetch options for React Bricks API calls. For example, pass Next.js `fetch` options or an `apiPrefix` for projects using a custom React Bricks API endpoint. | Older starters may use the positional signature: ```ts fetchPage(slug, apiKey, language?, pageTypes?) ``` ## Return value `fetchPage` returns a **promise which resolves to a [`Page`](/api-reference/types-reference/types/#page)** Before using this page with ReactBricks' [`PageViewer`](/api-reference/components/page-viewer) component, you need to parse it with the [`cleanPage`](/api-reference/utilities/clean-page) function. ## Usage example ```ts const page = await fetchPage({ slug: 'about-us', language: 'en', config, }) const myPage = cleanPage(page, pageTypes, bricks) console.log(myPage.content) ``` ## Usage with A/B Testing When a page uses A/B Testing, read the stable variant from the request cookies and pass it as `variantName`. ```ts import { cookies } from 'next/headers' import { fetchPage, getAbTestingCookie } from 'react-bricks/rsc' const cookieStore = await cookies() const variantName = getAbTestingCookie({ slug: cleanSlug, locale, cookieStore, }) const page = await fetchPage({ slug: cleanSlug, language: locale, variantName, config, fetchOptions: { next: { revalidate: 3 } }, }) ``` # fetchPages > Function to retrieve all your pages from outside the React context. The fetchPages function is useful when you want to **retrieve all your pages from outside the React context** (where you could use the [usePagesPublic hook](/api-reference/hooks/use-pages-public) instead). In particular, this comes in handy to retrieve all pages during the build process of a static website. This is the method used in React Bricks starter projects to generate routes and lists from published content. ## Signature (simplified) ```ts const fetchPages = async ( apiKey: string, options: {...} ): Promise ``` | Property | Definition | | --------- | ------------------------------------------------ | | `apiKey` | Api Key of your React Bricks app (a string). | | `options` | Optional object to filter the pages (see below). | ## Options The options object has the following shape ```ts { type?: string types?: string[] tag?: string language?: string usePagination?: boolean page?: number pageSize?: number sort?: string filterBy?: { [key: string]: any} } ``` | Property | Definition | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | Optional string to return only the pages with the specified page type. | | `types` | Optional array of strings to return only the pages with one of the specified page types. | | `tag` | Optional string to return only the pages with the specified tag. | | `language` | Optional string to return only the pages with the specified language. | | `usePagination` | If true, it will consider the page and pageSize parameters and it will return paginated results | | `page` | The page number, in case of pagination | | `pageSize` | The page size, in case of pagination | | `sort` | Sort parameter: currently it accepts only `createdAt`,`-createdAt`,`publishedAt`,`-publishedAt` | | `filterBy` | Used to filter by a custom field. The object should have a key for each field and the value that it should have (or an array of possible values). The queries on the fields are in logical AND. For example: `{ category: 'shoes', subcategory: ['snickers', 'running'] }`. At the moment you cannot filter using a complex type (like an object) for the value, so really now it should be `string` or `string[]` } | ## Return value `fetchPages` returns a **promise which resolves to**. - When `usePagination` is `false`, an array of type [PageFromList](/api-reference/types-reference/types#pagefromlist) - When `usePagination` is `true`, an object of type [PagesFromListWithPagination](/api-reference/types-reference/types#pagefromlistwithpagination) To retrieve the content of each page, you can use the [fetchPage](/api-reference/utilities/fetch-page) function. ## Usage example ```ts title="generateStaticParams.ts" import { fetchPages } from 'react-bricks/frontend' export async function generateStaticParams() { const products = await fetchPages(process.env.API_KEY!, { type: 'product', filterBy: { category: 'shoes', featured: 'true', }, sort: '-publishedAt', }) const items = Array.isArray(products) ? products : products.items return items.map((product) => ({ slug: product.slug, })) } ``` :::tip[Practical how-to] For a broader comparison between ``, `usePagesPublic`, and `fetchPages`, see [List pages by type](https://www.reactbricks.com/how-tos/page-types/list-pages-by-type). ::: # fetchTags > Function to retrieve all your tags from outside the React context. The fetchPages function is useful when you want to **retrieve all your tags from outside the React context** (where you could use the [useTagsPublic hook](/api-reference/hooks/use-tags-public) instead). In particular, this comes in handy to retrieve all the tags during the build process of a static website. ## Signature ```ts const fetchTags = async ( apiKey: string, page: number = 1, pageSize: number = 100 ): Promise<{ items: string[] pagination: { page: number pageSize: number totalItems: number totalPages: number } }> ``` | Property | Definition | | ---------- | -------------------------------------------- | | `apiKey` | Api Key of your React Bricks app (a string). | | `page` | Pagination's Page number | | `pageSize` | Pagination's Page size | ## Usage example ```ts {4} import { fetchTags } from 'react-bricks/frontend' import config from '../react-bricks/config' const paginatedTags = await fetchTags(config.apiKey) ``` # getAbTestingCookie > Function to read the React Bricks A/B Testing variant name from request cookies. `getAbTestingCookie` reads the A/B Testing variant name stored in the request cookies. Use it when rendering a page on the server so the same visitor keeps receiving the same variant. ## Signature ```ts import { cookies } from 'next/headers' type CookieStore = Awaited> const getAbTestingCookie = ({ slug, locale, cookieStore, }: { slug: string locale: string cookieStore: CookieStore }): string | undefined ``` | Property | Definition | | ------------- | ----------------------------------------- | | `slug` | The page slug for the current request. | | `locale` | The current locale. | | `cookieStore` | The cookie store returned by `cookies()`. | ## Usage example In a Next.js App route, get the cookie store using `cookies()` from `next/headers`, then pass the variant name to [`fetchPage`](/api-reference/utilities/fetch-page/). ```tsx import { cookies } from 'next/headers' import { fetchPage, getAbTestingCookie } from 'react-bricks/rsc' const cookieStore = await cookies() const variantName = getAbTestingCookie({ slug: cleanSlug, locale, cookieStore, }) const page = await fetchPage({ slug: cleanSlug, language: locale, variantName, config, }) ``` ## Related docs - [Implement A/B Testing](/common-tasks/implement-ab-testing/) - [`fetchPage`](/api-reference/utilities/fetch-page/) # getPagePlainText > Function to return an array of plain text strings with all the texts found in the page. Given a `Page` content (of type [`IContentBlock[]`](/api-reference/types-reference/interfaces#icontentblock)), this function **returns an array of plain text strings** with all the texts found in the page. It could be useful for page content indexing. # markPluginConstructor > Create a custom RichTextExt mark plugin with the markPluginConstructor helper. As we saw, the [RichTextExt](/api-reference/visual-components/rich-text-ext) can be extended using a plugin system. For a typical Mark plugin (bold, italic, highlight...), React Bricks provides the `markPluginConstructor` helper that allows you to create a new plugin very quickly. It just accepts a simple `MarkPlugin` object: ```ts type MarkPluginConstructor = (markPlugin: MarkPlugin) => RichTextPlugin interface MarkPlugin { name: string label?: string hotKey?: string render: (props: RenderLeafProps) => React.ReactElement icon?: React.ReactElement } ``` For the meaning of the arguments, you can see the interface for a [`RichTextPlugin`](/api-reference/visual-components/rich-text-ext). The `icon` is the button's icon. ## Usage example Here's the code for React Bricks `bold` plugin, created using the `markPluginConstructor` ```tsx import React from 'react' import { FaBold } from 'react-icons/fa' import { markPluginConstructor } from 'react-bricks/frontend' const plugin = markPluginConstructor({ name: 'bold', hotKey: 'mod+b', render: (props: any) => {props.children}, icon: , }) export default plugin ``` # Plain > Serialize and deserialize React Bricks rich text values as plain text. Plain text serializer / deserializer for a (Rich)Text value. It has the `deserialize` method to convert a `string` into an editor value and the `serialize` method which does the opposite. It is exported for compatibility and convenience, but there should be no use case for a user to directly call this two methods. # sendFormSubmission > Function to submit visitor form data to a React Bricks form. `sendFormSubmission` sends form data from a form brick to a React Bricks form configured in the dashboard. Use it when your project uses [Form Management](/cms-features/form-management/) and you need a frontend form to trigger the configured form actions. ## Signature ```ts const sendFormSubmission = async ({ appId, appEnv, token, formId, emailAddress, data, fetchOptions, }: SendFormSubmissionParams): Promise ``` ## Parameters ```ts interface SendFormSubmissionParams { appId: string appEnv: string token: string formId: string emailAddress: string data: Record fetchOptions: types.FetchOptions } ``` | Parameter | Definition | | -------------- | ------------------------------------------------------------------------------------------------- | | `appId` | The React Bricks app ID. | | `appEnv` | The React Bricks environment. | | `token` | The form submission token. | | `formId` | The ID of the form configured in React Bricks. | | `emailAddress` | The submitter email address. | | `data` | Object containing the submitted form values. | | `fetchOptions` | Fetch options for React Bricks API calls. For example, pass `{ apiPrefix: rbContext.apiPrefix }`. | ## Return value ```ts interface SendFormSubmissionResult { success: boolean statusCode: number message: string } ``` | Property | Definition | | ------------ | ----------------------------------------------------- | | `success` | `true` when the form submission was accepted. | | `statusCode` | HTTP status code returned by the submission endpoint. | | `message` | Message describing the result of the form submission. | ## Usage example `sendFormSubmission` is typically called from a form brick submit handler. The brick should collect field values, call `sendFormSubmission`, and then show a success or error state to the visitor. ```ts try { const result = await sendFormSubmission({ appId: rbContext.appId, appEnv: rbContext.environment, token, formId, emailAddress: email, data, fetchOptions: { apiPrefix: rbContext.apiPrefix }, }) if (result.success) { // Show a success state. } else { // Show result.message or a fallback error. } } catch (err) { // Handle network or unexpected errors. } ``` ## Form actions The function submits data to the form. The form configuration in the dashboard decides what happens next, such as: - saving submitted data - sending an email - subscribing the visitor to an Email Sending Provider list - calling a Zapier webhook ## Related docs - [Submit Forms](/common-tasks/submit-forms/) - [Form Management](/cms-features/form-management/) # File > Visual editing component to upload files and show them. The `File` component enables content creators to upload files. This feature is particularly useful when you need to include downloadable documents on your page, such as PDF catalogs or terms and conditions. You can specify which file extensions are allowed for each `File` component. ## Usage Example ```tsx import { File } from 'react-bricks/frontend' ... ( {name}, {size / 1024} KB )} /> ``` The JSX returned by the render function is displayed on both the frontend and the Editor interface. In the editor, content creators can upload a file by clicking on the rendered JSX. They can also remove a file or provide an SEO-friendly name (enforced via rewrite rules). You can render different elements on the frontend and admin interface by checking the `isAdmin` flag. :::tip[Practical how-to] For a step-by-step guide, see [Use the File component](https://www.reactbricks.com/how-tos/create-a-brick/use-the-file-component). ::: ## Properties Here's the TypeScript interface for the props of the `File` component: ```ts interface FileProps { propName: string source?: types.IFileSource renderBlock: (props: types.IFileSource) => JSX.Element allowedExtensions?: string[] } interface IFileSource { name: string // file name url: string size: number // size in bytes extension: string pagesNum: number title?: string | undefined alt?: string | undefined copyright?: string | undefined source?: string | undefined } ``` ## Properties definition | Property | Definition | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `propName` | The prop corresponding to this file. | | `renderBlock` | Render function to render the document on the page. Its argument is the file source object, including `name`, `url`, `size`, `extension`, `pagesNum` and optional metadata fields. | | `allowedExtensions` | Array of strings representing the allowed extensions. | ### Allowed extensions Allowed extensions must be a subset of the following: `.pdf`, `.bmp`, `.gif`, `.jpg`, `.jpeg`, `.png`, `.svg`, `.tif`, `.tiff`, `.webp`, `.mp4`, `.txt`, `.rtf`. Extensions not listed above are not allowed, even if specified in the `allowedExtensions` array. # Icon > Use the React Bricks Icon visual component to select and render icons in bricks. The `Icon` component isn't really a visual editing component—rather, it renders an SVG icon that users choose through a sidebar `IconSelector` control. The component accepts an `icon` prop of type [Icon](/api-reference/types-reference/types#icon), matching what's returned by an [IconSelector](/bricks/schema/side-edit-props/#icon-selector) sidebar control. By rendering an inline ``, it offers both performance (avoiding GET requests) and flexibility. You can customize it with any `className`, `width`, `height`, or other SVG props, and even preprocess the file before rendering. ## Usage Example ```tsx // Import from 'react-bricks/rsc/client' for Server components import { Icon } from 'react-bricks/frontend' ... ``` ## Properties Here's the (simplified) TypeScript interface for the props of the `Icon` component, which inherits all the props of a normal SVG, like `className`, `width`, `height`, etc.: ```ts interface IconProps extends React.SVGProps { icon: types.Icon description?: string preProcessor?: (code: string) => string title?: string | null } ``` ## Properties definition | Property | Definition | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `icon` | The icon object of type [Icon](/api-reference/types-reference/types#icon), typically set by a sideEditProp of type [IconSelector](/bricks/schema/side-edit-props/#icon-selector). | | `description` | Optional description. It will override an existing `` tag | | `preProcessor` | A function to process the contents of the SVG text before parsing. | | `title` | Optional title. It will override an existing `` tag. If `null` is passed, the `<title>` tag will be removed. | ### Preprocessor example Here's an example of using `preProcessor` to process the SVG content. ```ts preProcessor={(code) => code.replace(/fill=".*?"/g, 'fill="currentColor"')} ``` In case of icons from an IconSelector the previous code would not be needed, as icons have already `fill="currentColor"` for any path. # Image > Visual editing component to upload images, optimize and display them. The `Image` component enables content editors to upload/select and modify images. Required properties: - `propName`: the name of the prop - `source`: prop value. It is strictly required only for RSC, but we recommend always providing it for Server Components compatibility. ## Other frequently used props: - `aspectRatio`: forces editors to crop an image with a fixed aspect ratio (e.g. `16 : 9`) - `alt`: fallback alternate text, used if editors don't provide ALT text via the interface - `maxWidth`: instructs React Bricks image optimization on the maximum displayed size for this image - `quality`: sets the image compression quality (default 80) - `sizes`: provides fine-tuned image direction via the "sizes" attribute - `imageClassName`: class name applied to the rendered image ## Usage example ```jsx {9-15} import { types, Image } from 'react-bricks/frontend' interface MyBrickProps { image: types.IImageSource } const MyBrick: types.Brick<MyBrickProps> = ({ image }) => ( ... <Image propName="image" source={image} alt="Product" maxWidth="650" aspectRatio="1.33" /> ... ) MyBrick.schema = { ... } export default MyBrick ``` ## Rendering - On the frontend, the `Image` component displays a responsive, optimized image with progressive loading (lazy load). - In the Admin interface, it allows editors to **replace an image** by opening a modal where they can: - Replace an image from the media library, Unsplash, upload, or URL - Apply transformations (crop, rotate, flip) - Set the alternate text (ALT), SEO-friendly name (for the image URL), and priority for images above the fold ## Optimization To boost performance and SEO, upon upload, React Bricks will: - **Create responsive optimized images** - **Create the srcSet** for optimal image selection on the frontend - Create a lightweight **blurred placeholder** for progressive loading when the native lazy loading is unavailable - Serve images from a **global CDN** - Enforce **SEO-friendly name** via proper rewrite rules ## Readonly To render an image loaded in React Bricks as read-only, add the `readonly` flag. A common use case is rendering blog post thumbnails in a list of posts loaded via the `fetchPages` function. You can render a thumbnail for each post using `<Image readonly source={...}>`. ## Bind to Meta data or Custom fields As for Text and RichText, you can also bind an image to a page's custom field or meta image by replacing `propName` with `customFieldName` or `metaFieldName`. This creates a two-way data binding between the visual editing component and the images set via sidebar controls in the "Page" tab. :::tip[Practical how-to] For a step-by-step guide, see [Add an editable image](https://www.reactbricks.com/how-tos/create-a-brick/add-an-editable-image). ::: ## Properties Here's the Typescript interface for the props of the `Image` component: ```ts {29-30, 39-40} // For both editable and readonly images interface SharedImageProps { readonly?: boolean source?: types.IImageSource alt: string noLazyLoad?: boolean imageClassName?: string imageStyle?: React.CSSProperties quality?: number sizes?: string loading?: 'lazy' | 'eager' renderWrapper?: ({ children: React.ReactNode width?: number height?: number }) => React.ReactElement useNativeLazyLoading?: boolean useWebP?: boolean placeholder?: (props: { aspectRatio?: number maxWidth?: number isDarkColorMode?: boolean isAdmin: boolean }) => string } // For editable images interface EditableImage extends SharedImageProps { readonly?: false propName?: string metaFieldName?: 'image' customFieldName?: string aspectRatio?: number maxWidth?: number } // For readonly images interface ReadOnlyImage extends SharedImageProps { readonly: true source: types.IImageSource } /** * Props for Image */ type ImageProps = EditableImage | ReadOnlyImage ``` ## Properties definition | Property | Definition | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `propName` | The prop of the Brick component corresponding to this image. | | `source` | The value of the prop for this image. Required for Server Components, but always recommended for RSC compatibility | | `alt` | The fallback alternate text for the image when not provided via the upload modal | | `maxWidth` | The maximum width in pixel at which your image will be displayed. Used to calculate the responsive images for normal and retina displays. Default value is 800. | | `noLazyLoad` | Set to `true` to avoid lazy loading. Default is `false`. | | `aspectRatio` | If set, provides a fixed-ratio selection mask to crop the uploaded image. | | `imageClassName` | Optional className to apply to the `<img>` tag. | | `imageStyle` | Optional style object to apply to the `<img>` tag. | | `sizes` | Optional string to set the `sizes` attribute on the image for responsive images serving. | | `loading` | Optional prop to change the `loading` attribute for native lazy loading. Default is `lazy`. Usually, the default behaviour suffices. | | `renderWrapper` | Optional render function for a custom wrapper around the image. Provides `children`, `width` and `height` as arguments (width and height are from the original image size, useful for calculating aspect ratio). | | `useNativeLazyLoading` | The default is `true`: if browser support for native lazy loading is detected, it is used instead of our lazy loading system. Set to `false` to always use the custom lazy loading. | | `useWebP` | The default is `true`: creates `WebP` images upon upload, keeping JPEG (or PNG for transparency) as fallbacks without WebP support. Set to `false` to skip `WebP` creation. | | `metaFieldName` | Binds the image value to a page Meta field (two-way data binding) | | `customFieldName` | Bind the image value to a page Custom field (two-way data binding) | | `placeholder` | Function to customize the default image placeholder. Receives `{ aspectRatio, maxWidth, isDarkColorMode, isAdmin }` and should return a string URL. For custom placeholders, explicitly avoid rendering if `isAdmin` is false to prevent frontend display. | | `readonly` | Default is `false`. If `true`, the image is read-only, without an editing interface. | | `quality` | Quality of the optimized image (applied to WebP and JPEG images). Default is 80. | | _DEPRECATED_ | _The following properties still work but are deprecated_ | | `containerClassName` | Optional className for the image container (a thin wrapper created by React Bricks).<br />DEPRECATED since 3.3.0 as no wrapper is created anymore. Use `renderWrapper` instead. | | `containerStyle` | Optional style object to apply to the image container.<br />DEPRECATED since 3.3.0 as no wrapper is created anymore: use `renderWrapper` instead. | | `noWrapper` | Optional flag to avoid the wrapping `<div>` around the image. Default is `false`. <br />DEPRECATED since 3.3.0 as no wrapper is created anymore. | ## Usage with Server Components When working with Server Components, you need to import from `'react-bricks/rsc'`: ```tsx import { types, Image } from 'react-bricks/rsc' ``` # The Link component > Visual editing component to render local or external links. The Link component simplifies the management of links, both standalone and within RichText fields. When you enable Links in a RichText without customizing the render function, a `Link` component is automatically used to render links. ## Link Component vs. Standard Anchor 1. The Link component utilizes the framework's Link (e.g., Next.js Link) for local paths, while rendering a standard `<a>` tag for absolute URLs 2. In the Editor interface, the Link component doesn't trigger a link when clicked, allowing easy text editing within a link using a `<Text>` component. ## Standalone Usage Example ```tsx title="Button.tsx" import { Text, Link, types } from 'react-bricks/frontend' interface ButtonProps { buttonText: types.TextValue buttonPath: string } const Button: types.Brick<ButtonProps> = ({ buttonText, buttonPath }) => { return ( <Link href={buttonPath} className="py-2 px-6 text-white text-center bg-sky-500" > <Text propName="buttonText" value={buttonText} placeholder="Action" renderBlock={({ children }) => <span>{children}</span>} /> </Link> ) } Button.schema = { name: 'button', label: 'Button', getDefaultProps: () => ({ buttonText: 'Learn more', }), sideEditProps: [ { name: 'buttonPath', label: 'Path or URL', type: types.SideEditPropType.Text, validate: (value) => value?.startsWith('/') || value?.startsWith('https://') || 'Please, enter a valid URL', }, ], } export default Button ``` ## Usage inside a RichText {/* prettier-ignore */} ```tsx import { Link } from 'react-bricks/frontend' // ... <RichText propName="description" value={description} renderBlock={({ children }) => ( <p className="text-lg text-gray-500">{children}</p> )} placeholder="Type a description" allowedFeatures={[types.RichTextFeatures.Link]} renderLink={({ children, href, target, rel }) => ( <Link href={href} target={target} rel={rel} className="text-sky-500 hover:text-sky-600 transition-colors" > {children} </Link> )} /> ``` When editors opt to open a link in a new tab through the link popup interface, the attributes `target="_blank"` and `rel="noopener"` are automatically applied. ## Properties ```ts interface LinkProps { href: string target?: string rel?: string className?: string } ``` ## Properties Definition | Property | Definition | | ----------- | ---------------------------------------------------------------- | | `href` | The URL for an external link or the local path for a local link. | | `target` | The target for the external link (for example _"\_blank"_). | | `rel` | The "rel" for the external link (for example _"noopener"_). | | `className` | CSS class to be applied to the link tag. | The Link component also spreads `{...rest}` properties on the link tag or framework's Link component. ## Usage with Server Components When working with Server Components, you need to import from `'react-bricks/rsc'`: ```tsx import { types, Link, RichText } from 'react-bricks/rsc' ``` # Repeater > Visual editing component to create a repeating set of bricks inside another brick. import { Steps } from '@astrojs/starlight/components' React Bricks allows for infinite nesting of bricks within bricks using the `<Repeater>` component. Each Repeater can contain either a single repeatable brick type or multiple types. ## Usage example Let's consider the following "Button" brick that we want to repeat inside a "TextImage" brick: ```tsx title="Button.tsx" import { types, Link, Text } from 'react-bricks/frontend' import clsx from 'clsx' export interface ButtonProps { path: string buttonText: types.TextValue } const Button: types.Brick<ButtonProps> = ({ path, buttonText }) => ( <div> <Link href={path} className="inline-block text-center font-semibold leading-6 rounded-full px-8 py-3 border text-white bg-indigo-500 hover:bg-indigo-500/90 transition-colors border-indigo-500" > <Text propName="buttonText" value={buttonText} placeholder="Type a buttonText..." renderBlock={({ children }) => <span>{children}</span>} /> </Link> </div> ) Button.schema = { name: 'my-button', label: 'Button', hideFromAddMenu: true, getDefaultProps: () => ({ buttonText: 'Learn more', }), sideEditProps: [ { name: 'path', label: 'Path', type: types.SideEditPropType.Text }, ], } export default Button ``` In our TextImage brick, we need to: <Steps> 1. Add a prop in our interface for the repeated buttons 2. Add a `<Repeater>` component in the rendered JSX where items should appear 3. Add the `repeaterProps` in the brick's `schema` to specify the type of brick to be repeated </Steps> ### 1. Add a prop in the brick interface: ```tsx title="TextImage.tsx" {5} interface TextImageProps { title: types.TextValue description: types.TextValue image: types.IImageSource buttons: types.RepeaterItems<ButtonProps> } ``` ### 2. Add the `Repeater` component: ```tsx title="TextImage.tsx" // ... <Repeater propName="buttons" items={buttons} renderWrapper={(items) => ( <div className="flex gap-4 flex-wrap mt-6">{items}</div> )} /> // ... ``` ### 3. Add `repeaterItems` in the schema ```tsx title="TextImage.tsx" {5-12} TextImage.schema = { name: 'text-image', label: 'Text Image', ... repeaterItems: [ { name: 'buttons', itemType: 'my-button', itemLabel: 'Button', max: 2, }, ], ... } ``` Note that the name `buttons` is the same for both the Repeater's `propName` and the item name in the `repeaterItems`. In this example, our Repeater allows only one type of brick to be repeated (`my-button`). By setting `max: 2`, we limit the number of buttons that can be added in the repeater. :::tip It's advisable for the repeated brick to have a root `div` element. This allows React Bricks to properly attach focus events to the element. ::: ## Repeater Properties ```ts interface RepeaterProps { propName: string items?: types.RepeaterItems<T> itemProps?: types.Props renderWrapper?: (items: React.ReactElement) => React.ReactElement renderItemWrapper?: ( item: React.ReactElement, index?: number, itemsCount?: number ) => React.ReactElement } ``` ### Repeater Properties definition | Property | Definition | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `propName` | Name of the prop containing the repeated items (should match the one in the [`repeaterItems` schema property](/bricks/schema/repeater-items)) | | `items` | The value of the prop for this repeater, containing the repeated items. Required for Server Components, but always recommended for RSC compatibility | | `itemProps?` | Optional object with props passed to all the items (e.g., a global configuration shared by all the items). | | `renderWrapper?` | Optional function taking `items` as an argument. It should return JSX that wraps the items. Rendered only if there is at least one repeated item. | | `renderItemWrapper?` | Optional wrapper around each item. Takes `item`, `index` and `itemsCount` as arguments and should return JSX | ## The schema's `repeaterItems` Property While there's a dedicated section in the docs about the bricks' schema, we'll include the interface for `repeaterItems` here due to its close relation to the Repeater component. ```ts repeaterItems?: IRepeaterItem[] ``` Where `IRepeaterItem` is defined as: ```ts interface IRepeaterItem<T = any> { name: string label?: string itemType?: string itemLabel?: string defaultOpen?: boolean min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean items?: { type: string label?: string min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean }[] } ``` When `max` is reached, no more blocks can be added to the repeater. Setting a `min` ensures that React Bricks always maintains at least that number of blocks (adding items with default values). ### RepeaterItem Properties definition | Property | Definition | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Name of the prop containing the repeated items (e.g., "buttons") | | `itemType` | Corresponds to the unique `name` of the repeated Brick type (e.g., "my-button") | | `label?` | Label for the group of items in this repeater (title of nested items) | | `itemLabel?` | Optional label used for the Add / Remove buttons. If not provided, the repeated brick's label is used as a fallback | | `min` | Minimum number of repeated items allowed | | `max` | Maximum number of repeated items allowed | | `getDefaultProps` | Function that returns the default props for the repeated brick inside of this brick. For example, for a Button brick repeated inside a Form brick, you could specify that the default type should be "submit" instead of "link". | | `show` | Optional function to conditionally show the repeater item based on the current props, page and user. | | `items` | Allowed item types, when multiple. In this case the main `itemType` and `min` are not considered. Each item has its own `type`, `label`, `min`, `max`, `getDefaultProps` and `show`. | ### Multiple item types - `itemType` is used for a single type of brick that can be repeated in a Repeater (e.g. a Thumbnail in a Gallery). - `items` is used for multiple types of brick in a Reapear (e.g., in a Form you may add "TextInput" blocks or "Select" blocks). - With multiple item types, each with its own `min` and `max`, the root item's `min` is ignored, while the overall `max` is still enforced. ## Hiding a Repeated Brick from the Brick Selection Sometimes a brick is designed to be used only within another brick, and you don't want editors to add it directly to a page as a standalone element. For example, you might have a `GalleryImage` brick that should only appear inside a `Gallery` brick. To prevent such a brick from showing up in the list of available bricks when adding a new block, set `hideFromAddMenu: true` in the brick's [Schema](/bricks/schema). ## Usage with Server components When working with Server Components, you need to import from `'react-bricks/rsc'`: ```tsx import { types, Repeater, Text } from 'react-bricks/rsc' ``` see more in the [Server Components documentation](/rsc). # RichText > Visual editing component to edit rich text in React Bricks. The `RichText` component enables content editors to edit a multiline rich text. It is similar to the [`Text`](/api-reference/visual-components/text) component, but it allows you to select which rich text features editors can use, such as `bold`, `italic`, `link`, `highlight`, `quote`, `code`, `headings (H1..H6)`, `ordered list`, `unordered list`, `superscript`, and `subscript`. You can also customize the default render function for each style. Required properties: - `propName`: the name of the prop - `value`: prop value. It is strictly required only for RSC, but we recommend always providing it for Server Components compatibility. - `renderBlock`: the render function for this text (not strictly required, defaults to a simple `<span>` if omitted) - `allowedFeatures`: the available rich-text features (none by default) ## Usage example ```tsx {18-21, 38-42, 45-54} // from 'react-bricks/rsc' for usage with server components import { types, RichText, Link } from 'react-bricks/frontend' interface MyBrickProps { description: types.TextValue } const MyBrick: types.Brick<MyBrickProps> = ({ description }) => ( ... <RichText propName="description" value={description} renderBlock={({ children }) => ( <p className="text-lg text-gray-600">{children}</p> )} placeholder="Type a description..." allowedFeatures={[ types.RichTextFeatures.Bold, types.RichTextFeatures.Italic, types.RichTextFeatures.Link, //types.RichTextFeatures.Highlight, //types.RichTextFeatures.Heading1, //types.RichTextFeatures.Heading2, //types.RichTextFeatures.Heading3, //types.RichTextFeatures.Heading4, //types.RichTextFeatures.Heading5, //types.RichTextFeatures.Heading6, //types.RichTextFeatures.Code, //types.RichTextFeatures.Quote, //types.RichTextFeatures.OrderedList, //types.RichTextFeatures.UnorderedList, //types.RichTextFeatures.Subscript, //types.RichTextFeatures.Superscript, ]} // Override default <b> tag for Bold style renderBold={({ children }) => ( <b className="text-pink-500"> {children} </b> )} // Override rendering for Links renderLink={({ children, href, target, rel }) => ( <Link href={href} target={target} rel={rel} className="text-sky-500 hover:text-sky-600 transition-colors" > {children} </Link> )} /> ... ) MyBrick.schema = { ... } export default MyBrick ``` :::tip[Practical how-to] For step-by-step examples, see [Add rich text](https://www.reactbricks.com/how-tos/create-a-brick/add-rich-text) and [Customize rich text styles](https://www.reactbricks.com/how-tos/create-a-brick/customize-rich-text-styles). ::: ## Multi-line By default, the RichText component allows multiple lines of text. You can modify this behavior with these props: - `multiline` (default: true): if false, prevents the content editor from creating multiple lines with the `Enter` key - `softLineBreak` (default: true): if false, disables the soft line break (`<br />`) ## Bind to Meta data or Custom fields Typically, a RichText component is used to save a text value for the current block in the page. You can also bind it to a page's custom field or meta field by using `customFieldName` or `metaFieldName` instead of `propName`. This creates a two-way data binding between the visual editing component and the values in the sidebar controls of the "Page" tab. For custom fields, you can opt to save the value as plain text using the `customFieldPlainText` prop. ## Properties Here's the Typescript interface for the `RichText` component props: ```ts {3-8, 30-31, 40, 49-50} // For every RichText usage interface BaseRichTextProps { renderBlock?: (props: { children: React.ReactNode }) => JSX.Element placeholder?: string renderPlaceholder?: (props: { children: React.ReactNode }) => JSX.Element multiline?: boolean softLineBreak?: boolean allowedFeatures?: types.RichTextFeatures[] renderBold?: (props: { children: React.ReactNode }) => JSX.Element renderItalic?: (props: { children: React.ReactNode }) => JSX.Element renderHighlight?: (props: { children: React.ReactNode }) => JSX.Element renderCode?: (props: { children: React.ReactNode }) => JSX.Element rendersSub?: (props: { children: React.ReactNode }) => JSX.Element renderSup?: (props: { children: React.ReactNode }) => JSX.Element renderLink?: (props: { href: string, target?: string. rel?: string }) => JSX.Element renderUL?: (props: { children: React.ReactNode }) => JSX.Element renderOL?: (props: { children: React.ReactNode }) => JSX.Element renderLI?: (props: { children: React.ReactNode }) => JSX.Element renderH1?: (props: { children: React.ReactNode }) => JSX.Element renderH2?: (props: { children: React.ReactNode }) => JSX.Element renderH3?: (props: { children: React.ReactNode }) => JSX.Element renderH4?: (props: { children: React.ReactNode }) => JSX.Element renderH5?: (props: { children: React.ReactNode }) => JSX.Element renderH6?: (props: { children: React.ReactNode }) => JSX.Element renderQuote?: (props: { children: React.ReactNode }) => JSX.Element } // Usage with propName (usual case) interface RichTextPropsWithPropName extends BaseRichTextProps { propName: string value?: types.TextValue metaFieldName?: never customFieldName?: never customFieldPlainText?: never } interface RichTextPropsWithMetaFieldName extends BaseRichTextProps { propName?: never value?: never metaFieldName: 'title' | 'description' | 'language' customFieldName?: never customFieldPlainText?: never } interface RichTextPropsWithCustomFieldName extends BaseRichTextProps { propName?: never value?: never metaFieldName?: never customFieldName: string customFieldPlainText?: boolean } /** * Props for RichText component */ type RichTextProps = | RichTextPropsWithPropName | RichTextPropsWithMetaFieldName | RichTextPropsWithCustomFieldName ``` ## Properties definition | Property | Definition | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `propName` | The prop of the Brick component corresponding to this text. | | `value` | The value of the prop for this rich text. Required for Server Components, but always recommended for RSC compatibility | | `renderBlock` | A React functional component used to render each paragraph of text. | | `placeholder` | The placeholder to show when the text is empty. | | `renderPlaceholder` | A React functional component used to render the placeholder, for custom display. | | `multiline` | Default: `true`. If `false` it prevents multiline text. | | `softLineBreak` | Default: `true`. If `false` it prevents soft line breaks. | | `allowedFeatures` | An array of allowed rich text features: the available features are of type [`types.RichTextFeatures`](/api-reference/types-reference/enums#richtextfeatures) | | `metaFieldName` | Binds the text value to a page Meta field (two-way data binding) | | `customFieldName` | Binds the text value to a page Custom field (two-way data binding) | | `renderBold` | The optional render function for the `BOLD` marker. | | `renderItalic` | The optional render function for the `ITALIC` marker. | | `renderCode` | The optional render function for the `CODE` marker. | | `renderHighlight` | The optional render function for the `HIGHLIGHT` marker. | | `renderLink` | The optional render function for the `LINK` marker. **Warning**: this overrides the default React Bricks `Link` component (which uses the configured `renderLocalLink` for local links and a `<a>` tag for external links). | | `renderUL` | The optional render function for Unordered Lists. | | `renderOL` | The optional render function for Ordered Lists. | | `renderLI` | The optional render function for List Items. | | `renderH1..H6` | The optional render function for Headings. | | `renderQuote` | The optional render function for Quote. | | `renderSub` | The optional render function for Subscript. | | `renderSup` | The optional render function for Superscript. | ## Usage with Server Components When working with Server Components, you need to import from `'react-bricks/rsc'`: ```tsx import { types, RichText, Link } from 'react-bricks/rsc' ``` ## Create custom plugins To enhance the RichText component's default functionality, such as adding an emoji button, you can use the [RichTextExt](/api-reference/visual-components/rich-text-ext) component. This component is designed to be extended with custom plugins. With RichTextExt, you can develop sophisticated rich text features, including those requiring configuration popups with custom fields. For more information, see the [Extensible RichText](/api-reference/visual-components/rich-text-ext) documentation. # RichTextExt (Extensible RichText) > Extensible plugin-based Rich Text component to create custom rich-text plugins. The `RichTextExt` component is an extensible version of the [`RichText` component](/api-reference/visual-components/rich-text). Unlike the standard `RichText`, it employs a plugin system. This allows you to replace any part of a default plugin—not just the render function, but also the button icon, label, shortcut key, etc.—and add new plugins. > Note: for most use cases, you should use the normal [`RichText`](/api-reference/visual-components/rich-text), which is simpler to use. ## Usage Example In this example, we're not creating custom plugins. Instead, we're configuring the RichTextExt component to use predefined rich text plugins while overriding the shortcut key and render function of the "quote" plugin: ```tsx {1,12-26} import { RichTextExt as RichText, plugins } from 'react-bricks/frontend' const { bold, italic, unorderedList, link, quote } = plugins return ( <RichText renderBlock={({ children }) => ( <p className="text-lg sm:text-xl text-center">{props.children}</p> )} placeholder="Type a text..." propName="text" plugins={[ bold, italic, unorderedList, link, { ...quote, renderElement: ({ children }) => ( <div className="border-l-4 pl-4 border-pink-500 text-pink-500 text-xl"> {children} </div> ), hotKey: 'mod+opt+q', }, ]} /> ) ``` ## Properties Here's the Typescript interface for the props of the `RichTextExt` component: ```ts {12} interface RichTextProps { propName?: string value?: types.TextValue renderBlock?: (props: { children: React.ReactElement }) => JSX.Element placeholder?: string renderPlaceholder?: (props: { children: React.ReactElement }) => JSX.Element multiline?: boolean softLineBreak?: boolean metaFieldName?: 'title' | 'description' | 'language' customFieldName?: string customFieldPlainText?: boolean plugins?: types.RichTextPlugin[] } ``` ## Properties Definition For props shared with the RichText component, refer to the RichText documentation. Note that for RichTextExt, properties like allowedFeatures and all render functions (e.g., renderBold) are replaced by the plugins property. | Property | Definition | | --------- | ---------------------------------------------------------------------------------------- | | `plugins` | An array of plugins extending the rich text functionality, each of type `RichTextPlugin` | `RichTextPlugin` is defined as follows: ```ts interface RichTextPlugin { type: 'Mark' | 'Block' | 'List' name: string isInline?: boolean itemName?: string label: string hotKey?: string renderElement?: (props: RenderElementProps) => React.ReactElement renderItemElement?: (props: RenderElementProps) => React.ReactElement renderLeaf?: (props: RenderLeafProps) => React.ReactElement toggle: ( editor: Editor, plugins: RichTextPlugin[], showRichTextModal: types.ShowRichTextModal ) => void button?: { icon: React.ReactElement isActive: (editor: Editor) => boolean } enhanceEditor?: (editor: Editor) => Editor } ``` React Bricks uses [Slate](https://docs.slatejs.org/) as its underlying rich text editor. The `RenderElementProps` and `RenderLeafProps` are types from Slate. ## RichTextPlugin properties | Plugin | Definition | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `type` | A plugin can be of type "Mark" (a style like bold), "Block" (e.g., an heading) or "List" (for a list of items, like UL). | | `name` | Name of the plugin. | | `isInline?` | Indicates if the element is inline (e.g., for links). | | `itemName?` | Name of the items element in case of a list | | `label` | Displayed when hovering over the button | | `hotKey?` | Shortcut key to apply this marker or block type | | `renderElement?` | Render function for a block plugin. Key arguments: `children` (actual text content), `attributes` (to be spread on the top-level DOM element) and `element` (an object whose `type` is the plugin name). | | `renderItemElement?` | Render function for a single list item (e.g., a `li` element). | | `renderLeaf?` | Render function for a mark plugin (e.g., bold or italic). Arguments: `children`, `attributes` and `leaf`. Leaf is an object with truthy keys for applied markers (e.g. `if (leaf.bold) {...}`). | | `toggle` | Function to toggle the marker or block on the editor. | | `button` | Customizes the default button for a plugin or configures the button for a new plugin, providing the `icon` (a `ReactElement`) and a `isActive` function. | | `enhanceEditor` | Function to enhance the Slate editor. Returns an enhanced editor. Refer to [Slate documentation](https://docs.slatejs.org/). This is a very powerful option to customize the React Bricks RichText behavior. | ## Plugins helpers For common marker (bold, italic, highlight...) or block (heading, quote, etc.) plugins, React Bricks provides helpers that allow you to create new plugins very quickly: - [Mark plugins helper](/api-reference/utilities/mark-plugin-constructor) - [Block plugins helper](/api-reference/utilities/block-plugin-constructor) There's also a helper for creating complex plugins that require a popup configuration interface. This helper enables you to add custom fields of various types (such as text, select, and autocomplete) that content editors can modify. The plugin then uses these field values: - [Block with modal plugins helper](/api-reference/utilities/block-with-modal-plugin-constructor) # Text > Visual editing component to edit plain text in React Bricks. The `Text` component enables content editors to edit plain text. Required properties: - `propName`: the name of the prop - `value`: prop value. It is strictly required only for RSC, but we recommend always providing it for Server Components compatibility. - `renderBlock`: the render function for this text. It is not strictly required; if missing, it renders a simple `<span>`. ## Usage example ```tsx {10-17} // from 'react-bricks/rsc' for usage with server components import { types, Text } from 'react-bricks/frontend' interface MyBrickProps { title: types.TextValue } const MyBrick: types.Brick<MyBrickProps> = ({ title }) => ( ... <Text propName="title" value={title} renderBlock={({ children }) => ( <h1 className="text-xl font-extrabold">{children}</h1> )} placeholder="Title..." /> ... ) MyBrick.schema = { ... } export default MyBrick ``` :::tip[Practical how-to] For a step-by-step guide, see [Make text visually editable](https://www.reactbricks.com/how-tos/create-a-brick/make-text-visually-editable). ::: ## Multi-line By default, editors can enter a single line of text in a Text component. You can change this behavior by setting the following props: - `multiline` (false by default): it allows entering multiple lines, each rendering the JSX returned by the `renderBlock` function - `softLineBreak` (false by default): if true, it allows entering a soft line break (`<br />`) using `shift+enter` ## Bind to Meta data or Custom fields A Text component is typically used to save a text value for the current block in the page. You can also bind it to a page's custom field or meta field by replacing `propName` with `customFieldName` or `metaFieldName`. This creates a two-way data binding between the visual editing component and the values you can enter via the sidebar controls in the "Page" tab. This feature is useful, for example, when you want the title of a hero unit on the page to also set the meta title of the page directly. ## Properties Here's the Typescript interface for the props of the `Text` component: ```ts // Props for all the usages of Text interface BaseTextProps { renderBlock?: (props: RenderElementProps) => JSX.Element placeholder?: string renderPlaceholder?: (props: { children: any }) => JSX.Element multiline?: boolean softLineBreak?: boolean } // Usage with propName (usual case) interface TextPropsWithPropName extends BaseTextProps { propName: string value?: types.TextValue metaFieldName?: never customFieldName?: never } // Usage when binding to a Meta Field interface TextPropsWithMetaFieldName extends BaseTextProps { propName?: never value?: never metaFieldName: 'title' | 'description' | 'language' customFieldName?: never } // Usage when binding to a Custom Field interface TextPropsWithCustomFieldName extends BaseTextProps { propName?: never value?: never metaFieldName?: never customFieldName: string } /** * Props for Text component */ type TextProps = | TextPropsWithPropName | TextPropsWithMetaFieldName | TextPropsWithCustomFieldName ``` ## Properties definition | Property | Definition | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `propName` | The prop of the Brick component corresponding to this text. Mandatory unless you bind the value to a `metaFieldName` or `customFieldName` | | `value` | The value of the prop for this text. Required for Server Components, but always recommended for RSC compatibility | | `renderBlock` | A React functional component used to render the text. | | `placeholder` | The placeholder to show when the text is empty. | | `renderPlaceholder` | A React functional component used to render the placeholder, for custom display. | | `multiline` | Default: `false`. If `true` allows multiline text. | | `softLineBreak` | Default: `false`. If `true` allows soft line breaks. | | `metaFieldName` | Binds the text value to a page Meta field (two-way data binding) | | `customFieldName` | Binds the text value to a page Custom field (two-way data binding) | ## Usage with Server Components When working with Server Components, you need to import from `'react-bricks/rsc'`: ```tsx import { types, Text } from 'react-bricks/rsc' ``` # Admin Interface > Discover the Content Administration interface of React Bricks, with inline visual editing. import Video from '@components/Video' In the Starter projects, the Admin interface is accessible at the `/admin` path. It's pre-configured for you, using React Bricks' [`<Admin>`](/api-reference/components/admin), [`<Login>`](/api-reference/components/login), [`<Editor>`](/api-reference/components/editor), [`<MediaLibrary>`](/cms-features/digital-assets-manager), [`<Playground>`](/api-reference/components/playground) and [`<AppSettings>`](/api-reference/components/app-settings) components. By default, the Admin Interface offers four main views (unless you customize the Menu items): - [**Editor**](#editor): The primary view for creating pages and editing content. - [**Media**](/cms-features/digital-assets-manager): A comprehensive Digital Assets Management (DAM) system. - [**Playground**](#playground): A preview area for all [Bricks](/bricks/introduction) and [Page Types](/page-types) - [**Settings / Deploy**](#app-settings): Enables Editors to trigger static website rebuilds (for Netlify or Vercel hosting). Admins have a more powerful interface to access the React Bricks Dashboard where they can configure all the App settings and manage User invitations. <Video src="/videos/admin_interface/overview.mp4" /> ## Editor This section allows content creators ([Admin](/cms-features/permissions##default-user-roles) or [Editor](/cms-features/permissions#default-user-roles) users) to edit the website pages content. <Video src="/videos/admin_interface/editor.mp4" /> ### Left panel (Pages) The left panel displays Pages, organized by Page Type. Selecting a Page allows you to edit its content. ### Central panel (content editor) The central panel serves two main purposes: - Visual editing of block content (Text, Images) - Adding, removing, and reordering blocks ### Right panel (Page, Block, Item, Stories) The right panel consists of three tabs: - **Page**: Edit [page properties](/basics/pages-and-page-types), such as Name, Slug, Author, SEO attributes (Meta tags, OpenGraph, Twitter cards, Schema.org structured data), set the [page status](/basics/pages-and-page-types) (draft / published, locked / unlocked), schedule publishing, and delete the page. - **Block**: Edit block properties as defined in the Brick's [sideEditProps](/bricks/schema/side-edit-props) (e.g. background color, padding), and manage repeater items (used in `<Repeater>` components). - **Item**: Edit block properties of a repeater item - **Stories**: Save a brick's current state to apply the same text, images and props to other content blocks later. This feature allows you to create configuration templates for your bricks. Stories can both be created in code by developers, or by the editors. In this second case, they are stored on our APIs, ensuring persistence across users without code changes. ## Playground <Video src="/videos/admin_interface/playground.mp4" /> ### Left panel The left panel displays all Block types and, below them, all Page types. Clicking on a Block or Page reveals its details on the right. ### Central panel This panel shows the default content for a block or page. Here, you can test the block's functionality with WYSIWYG editing and side-edit props. You can also capture a component screenshot by clicking the pink button. The screenshot's image URL is copied to your clipboard, to set the `previewImageUrl` in the brick's schema. ### Right panel For a Brick, you'll be able to see all the editable sidebar controls and in which page types the brick is allowed. ## App Settings Admin users can access the [React Bricks Dashboard](https://dashboard.reactbricks.com) to configure every aspect of a React Bricks App. Users Users with Editor roles only see the "Deploy" button to initiate rebuilds. <Video src="/videos/admin_interface/app_settings.mp4" /> ## Click to edit When logged into the Admin interface and browsing the live website, you'll see a small pencil icon. Clicking this icon takes you directly to the Admin interface for editing the current page. <Video src="/videos/click_to_edit.mp4" /> Through [React Bricks configuration's](/common-tasks/customize-react-bricks/) `clickToEditSide` setting, which corner the "click to edit" button appears in, or disable it entirely (see [ClickToEditSide](/api-reference/types-reference/enums/#clicktoeditside)). # Bricks > A Brick is a visually editable content block for React Bricks created by developers in React and used by content editors to build pages. A Brick is a visually editable content block for React Bricks. Developers create these blocks, which content editors then use to build pages. ## Creating Custom Bricks Creating custom bricks is the heart of developing with React Bricks. This custom bricks form your unique "Lego set" of content blocks that embody your corporate image or that of your client. Within a Brick, developers define what's visually editable using React Bricks visual components. They also control the level of freedom given to content editors through sidebar controls—for example, allowing adjustments to properties like padding or background color. Since Bricks are simply React components, developers can easily start using React Bricks and convert existing components into visually editable bricks. # Deploy your site > Learn how to deploy your React Bricks site to Vercel, Netlify or any other Node-compatible hosting platform. import Video from '@components/Video' ## Hosting Requirements **You can host a React Bricks website almost anywhere.** You only need a hosting environment capable of running **Node.js** (to build the website, for Static Site Generation or to build pages at runtime, for Server Side Rendering). Any hosting platform such as [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), AWS, Azure will work perfectly. ## Environment variables **React Bricks needs 2 environment variables**. These are typically stored in your local `.env` file and must be set in the hosting provider's environment variables: - `APP_ID`: This variable must be **accessible by the browser** and is used by the Admin interface. - `API_KEY`: This is the secret API_KEY which should not be exposed to the browser. To expose the `APP_ID` variable to the browser, use the public environment variable convention for your framework, such as `NEXT_PUBLIC_APP_ID` for Next.js or `PUBLIC_APP_ID` for Astro. ## Build Hooks Providers like [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/), which connect to your Github or Bitbucket repo, can trigger a rebuild when you push changes to the repo. However, this doesn't address changes in CMS content. Most providers allow you to create a **Build hook**—a URL that, when called (typically via HTTP POST), **triggers a site rebuild**. **React Bricks allows the Admin to set up two deploy hooks** for an App: one for the **Production** environment and one for **Staging** (plus a third "Development" hook in case of Enterprise plans). These can be configured from the [React Bricks Dashboard](https://dashboard.reactbricks.com). The Admin can grant Editors permission to trigger Development, Staging or Production deploys by simply clicking a button in the App Settings interface. <Video src="/videos/dashboard/web-hooks.mp4" /> ### Events hook For Enterprise plan, you can also provide an Events web hook that will receive a notification for each event of pages (creation, update, delete, etc.), with a proper payload for each type of action. In this way you can implement a logging system or react to actions in an external application. # Pages, Page Types, Templates > A Page in React Bricks represent a unit of content. Pages can be organized in Page Types and be based on a Template. ## Pages A Page in React Bricks represent a **unit of content**. It corresponds to a website page or a blog post, but can also store content fragments reusable across different pages. A page has content, type, slug, name, author, meta values, statuses (visibility, lock, approval phase, etc.), tags, and creation date. The content of a page is an array of content blocks. Each block has an `id`, a `type` (referencing the corresponding brick name) and `props` to pass to the brick's component. A page can also be based on a Page Template. In this case, its content is more structured, as content blocks belong to one of the Template's Slots. ## Page Types Developer can define multiple Page Types in code through the `pageTypes` configuration. In the starter templates, you can edit Page Types in the `pageTypes.ts` file. Each Page Type has: - `name` (required): A unique string representing the page type - `pluralName` (required): Used by the content administration interface - `defaultLocked`: Boolean, default false - `defaultStatus`: `types.PageStatus.Published` or `types.PageStatus.Draft` - `getDefaultContent`: A function returning the default content (array of brick's names, stories or full content) - `isEntity`: Boolean, default false. If true, pages of this type appear in the "Entities" tab (useful for reusable fragments like Header, Footer, etc.). - `allowedBlockTypes`: Array of allowed bricks. If not provided, all bricks are allowed. - `getExternalData`: Async function (receiving the `page` object as an argument) that resolves to an object, fetching data from an external API. The returned data is available in the `externalData` object on the page and can be consumed directly (`usePageValues`) or from a single brick via the `mapExternalDataToProps` function in the brick's `schema`. - `getDefaultMeta`: Function (receiving the `page` object and `externalData` object as arguments) to return default meta values for a new page (e.g. set Schema.org data on a product from a headless commerce structured data). - `template`: An array of Slots defining a page template (see next section). ## Page Template Sometimes you want to restrict editors' freedom when composing a page. You might want fixed sections, blocks that can't be removed, areas where editors can use only a subset of bricks, or even non-editable sections. Templates serve this purpose. A `template` is an array of `slots`, where each slot has these properties: - `slotName` (required): The name of the slot, unique within this pageType - `label` (required): A label displayed in the editing interface - `allowedBlockTypes`: Array of strings with the names of allowed bricks - `getDefaultContent`: Function that returns the default content for the slot, with the same signature as `getDefaultContent` at pageType level - `min`: Minimum number of blocks (applied when there is only one type in `allowedBlockTypes`) - `max`: maximum number of blocks - `editable`: if false the slot is not editable at all # Project Structure > Learn the recommended file and folder structure for a React Bricks project. import { FileTree } from '@astrojs/starlight/components' A React Bricks project generated by the `create reactbricks-app` CLI includes various files and folders. The specific structure depends on your chosen framework, such as Next.js with the App Router, Next.js with the Pages Router, or Astro, and on the selected template project. ## Directories and Files Several directories and files are common to all generated projects: - `admin/*` - Content administration routes - `react-bricks/config.tsx` - React Bricks configuration file - `react-bricks/pageTypes.tsx` - Page Types configuration file - `react-bricks/bricks/*` - Bricks folder, usually with subfolders for each theme ### Example Project Tree A typical React Bricks project directory might look like this: :::note This is the case of a Next.js project with the App Router and Tailwind CSS. Your app structure may differ. ::: {/* prettier-ignore */} <FileTree> - app - [lang] - [[...slug]] - page.tsx - layout.tsx - admin - (sso)/ - app-settings - page.tsx - editor - page.tsx - media - page.tsx - playground - page.tsx - layout.tsx - page.tsx - ReactBricksApp.tsx - preview - layout.tsx - page.tsx - components/ - css/ - public/ - react-bricks - bricks - custom - MyHeroUnit.tsx - ... - react-bricks-ui/ - index.ts - config.tsx - NextLink.tsx - NextLinkClient.tsx - pageTypes.ts - .env.local - i18n-config.ts - middleware.ts - next.config.js - package.json - postcss.config.js - tailwind.config.ts - tsconfig.json </FileTree> Let's explore the key folders and files in the project tree: ### `react-bricks/` The `react-bricks/` folder houses the React Bricks configuration, including: - [Bricks](/basics/bricks) - [Page Types](/basics/pages-and-page-types) ### `react-bricks/bricks` This folder contains the bricks. You'll find pre-made bricks under `react-bricks-ui` and example custom bricks under `custom`. We recommend creating your own folder under `/bricks` to house bricks that implement your design system. ### `react-bricks/index.ts` This file imports all bricks and re-exports them in a theme > category structured tree. You can create your own theme and categorize bricks by type (e.g., hero units, calls to action, features). ### `react-bricks/pageTypes.ts` Here you can configure pageTypes. A pageType can have default content, a subset of usable bricks, custom fields, external data, or even define a full Page Template with Slots. ### `react-bricks/config.ts` The `config.ts` contains the React Bricks configuration and imports all bricks and pageTypes. ### `app/[lang]` This directory contains the "catch-all" routes of the frontend website. The structure here may vary significantly between frameworks, as the `app` folder is specific for Next.js with the App Router. ### `app/admin` This directory houses the content administration interface. It's hosted within your project, alongside the frontend website. ### `.env.local` This file isn't committed to the Git repo. The CLI configures it with your App's credentials (`APP_ID`, `API_KEY`, `ENVIRONMENT`). You can also add other environment variables here, such as an Unsplash API Key. # Embed Pages > In React Bricks you can embed a page or entity inside another page. import Video from '@components/Video' Sometimes you need a block or set of blocks that you can **reuse across different pages**. This allows changes to the original block(s) to be reflected on every page that embeds them (for example, a CTA with a newsletter subscription form). You can achieve this through **special "embed bricks"** that allow you to embed one page inside another. When you modify the original page, the changes automatically appear on every page that embeds it. :::note It's generally advisable to save these "reusable fragments"—which aren't full pages with a route in the website—using an Entity `pageType` (a page type with `isEntity` set to `true`). This prevents these fragments from appearing in the main pages list. ::: <Video src="/videos/adv-features/embed.mp4" /> ## The Default Embed Brick By default (unless disabled via the `enableDefaultEmbedBrick` configuration), you have access to a pre-made "embed brick" that allows editors to embed any page of any type. ## Custom Embed Brick You can create a custom embed brick that restricts editors to embedding only pages of a specific type. An embed brick must have a `sideEditProp` with name `types.EmbedProp`, of type `types.SideEditPropType.Relationship`. You can limit the pages an editor can select to just one `pageType` by using the `references` property of `relationshipOptions`. ### Example usage ```tsx const embedPageBrick: types.Brick = () => null embedPageBrick.schema = { name: 'product-embed', label: 'Embed Product', category: 'Embed', sideEditProps: [ { name: types.EmbedProp, // This triggers Embedding label: 'Embed a product', type: types.SideEditPropType.Relationship, relationshipOptions: { references: 'product', // You can choose to limit choice to just one pageType multiple: false, // Multiple not supported for embeds }, helperText: 'Choose a product, save to view it.', }, ], } ``` # Introduction to Bricks > What is a Brick (visually editable React component) and how it is structured. ## What is a Brick? A Brick is essentially a **React component**, that: 1. Uses React Bricks [**visual editing components**](/bricks/visual-editing) (Text, RichText, Image, Repeater, Link, File) in the JSX to enable inline **Visual Editing** of content; 2. Has a [**`schema` property**](/bricks/schema/) to define a unique name, default properties and specify **Sidebar Controls** that allow editors to modify certain props. Below, you'll find a simple brick example. In the following sections, we'll explore how to use React Bricks visual editing components and properly configure a brick's schema. ## Meet your first Brick Here's an example "Hero Unit" brick. In the JSX code, you'll notice a React Bricks `RichText` component that makes text visually editable. The `schema` defines the brick's name and includes a sidebar control of type `Select` allowing editors to adjust the padding. ```tsx {3,9,15,30, 39} title="HeroUnit.tsx" import { types, RichText } from 'react-bricks/frontend' // Component interface interface HeroUnitProps { title: types.TextValue padding: 'big' | 'small' } // The React Component const HeroUnit: types.Brick<HeroUnitProps> = ({ title, padding }) => { return ( <div className={`${padding === 'big' ? 'py-20' : 'py-12'}`}> <RichText propName="title" value={title} placeholder="Type a title..." renderBlock={({ children }) => ( <h1 className="text-3xl text-center">{children}</h1> )} allowedFeatures={[types.RichTextFeatures.Bold]} /> </div> ) } // The Brick's Schema HeroUnit.schema = { name: 'hero-unit', label: 'Hero Unit', getDefaultProps: () => ({ padding: 'big', title: 'Thick as a React Brick', }), // Sidebar Controls Definition sideEditProps: [ { name: 'padding', label: 'Padding', type: types.SideEditPropType.Select, selectOptions: { display: types.OptionsDisplay.Radio, options: [ { value: 'big', label: 'Big' }, { value: 'small', label: 'Small' }, ], }, }, ], } export default HeroUnit ``` ## Adding a brick to the React Bricks configuration After creating a new brick, you need to add it to the available bricks to make it visible in the Editor. You can find the available bricks in the `react-bricks/bricks/index.ts` file. Bricks are organized into **Themes**. A Theme is a set of bricks, usually grouped around the same design system, template package, or visual language. For example, if your company name is "Acme," you could create an "Acme" theme to host all your custom bricks that define Acme's website design system. Within each theme, bricks can be further organized into **Categories** (e.g., "Hero Sections," "CTAs," "Blog Content," "Features"). Themes can also define `bannerText` and `bannerLink`. These optional fields show a banner for the theme in the editor and are useful to link to design guidelines, documentation, or the purchase page of a premium theme. The Theme type has this shape: ```ts type Category = { categoryName: string bricks: Brick<any>[] } type Theme = { themeName: string bannerText?: string bannerLink?: string categories: Category[] } ``` Let's demonstrate how to add a "HeroUnit" brick to the Acme theme's bricks under the "Hero Sections" category: ```ts title="/react-bricks/bricks/index.ts" {3, 11} import { types } from 'react-bricks/rsc' import HeroUnit from './acme-theme/HeroUnit' const bricks: types.Theme[] = [ { themeName: 'Acme', bannerText: 'View Acme design guidelines', bannerLink: 'https://acme.com/design-system', categories: [ { categoryName: 'Hero Sections', bricks: [HeroUnit, ...], }, ], }, ] export default bricks ``` :::tip[Practical how-to] For a step-by-step guide, see [Create a custom brick](https://www.reactbricks.com/how-tos/create-a-brick/create-a-custom-brick). ::: # Schema > Define a React Bricks brick schema, including labels, props, sidebar controls, stories, and external data. import { CardGrid, LinkCard, Steps } from '@astrojs/starlight/components' Each brick requires a `schema` property, which defines the brick name, default props, sidebar controls and other things. ## Required props Th required props are just two: - `name`: a name for this brick. It must be unique within the bricks configured for an App - `label`: the name displayed for this brick in the editing interface Let's see a first simple example of a brick's `schema`: ## Usage Example ```tsx title="TextImage.tsx" {7} const TextImage: types.Brick<TextImageProps> = ({...}) => { return ( ... ) } TextImage.schema = { name: 'text-image', label: 'Text Image', previewImageUrl: imgPreview.src, getDefaultProps: () => ({ title: 'Thick as a brick', description: 'Another brick in the wall', imageSide: 'right', }), sideEditProps: [ { name: 'imageSide', label: 'Image Side', type: types.SideEditPropType.Select, selectOptions: { display: types.OptionsDisplay.Radio, options: [ { value: 'left', label: 'Left' }, { value: 'right', label: 'Right' }, ], }, }, ], } ``` ## Schema Properties Let's analyze the schema properties dividing them in 3 groups: ### 1. Key Properties Apart from name and label, there are other key properties defined in the `schema`. Click on the property to access the dedicated page in the documentation: <CardGrid> <LinkCard title="`getDefaultProps`" description="A function returning the default props for this brick, when it is added to a page." href="/bricks/schema/get-default-props" /> <LinkCard title="`sideEditProps`" description="Array of sidebar controls to let the editors adjust props. Controls can also be organized in collapsible groups." href="/bricks/schema/side-edit-props" /> <LinkCard title="`repeaterItems`" description="Used in conjunction with a `Repeater` to define the type of brick to be repeated." href="/bricks/schema/repeater-items" /> <LinkCard title="`stories`" description="Stories are a way to reuse a brick's configuration. They can be defined in code or saved by content editors." href="/bricks/schema/stories" /> <LinkCard title="`getExternalData` and `mapExternalDataToProps`" description="Directly fetch data from an external data source in a brick or map data from the Page Type to props of this brick" href="/common-tasks/get-data-from-external-apis/#fetch-external-data-in-a-brick" /> <LinkCard title="`astroInteractivity`" description="For Astro, specify the type of client interactivity (by default no JavaScript is sent to the client)." href="/bricks/schema/astro-interactivity" /> </CardGrid> ### 2. UI and Categorization | Property | Description | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `hideFromAddMenu` | Hide this brick from the "Add new brick" menu. Useful to prevent editors to add directly to a page bricks that are meant to be used only when repeated within another brick. | | `previewImageUrl` | Image of the brick shown in the "Add new brick" selection on the right sidebar. | | `tags` | A set of tags to help content editors find this brick with the search function (for example, add "cta", "call to action", "link" to a "CallToAction" brick) | | `playgroundLinkUrl` | Show a link in the Playground for this brick: for example to an external design guideline. | | `playgroundLinkLabel` | Label for the Playground link. | ## Typings for Schema ```ts title="Schema interface" interface IBlockType<T = Props> { name: string label: string description?: string getDefaultProps?: () => Partial<T> hideFromAddMenu?: boolean disabled?: boolean disabledIcon?: 'purchase' | 'maintenance' disabledLink?: string disabledTooltip?: string sideEditProps?: Array<ISideEditProp<T> | ISideGroup<T>> repeaterItems?: IRepeaterItem<T>[] newItemMenuOpen?: boolean groupByRepeater?: boolean mapExternalDataToProps?: (externalData: Props, brickProps?: T) => Partial<T> getExternalData?: ( page: Page, brickProps?: T, args?: any ) => Promise<Partial<T>> playgroundLinkUrl?: string playgroundLinkLabel?: string theme?: string category?: string tags?: string[] previewImageUrl?: string previewIcon?: React.ReactElement stories?: BrickStory<Partial<T>>[] astroInteractivity?: | 'load' | { load: true } | 'idle' | { idle: true } | { idle: { timeout: number } } | 'visible' | { visible: true } | { visible: { rootMargin: string } } | { media: string } | { only: string } } ``` :::note - The `ISideEditProp` / `ISideGroup` interface is explained in the [Side edit props](/bricks/schema/side-edit-props) page. - The `IRepeaterItem` interface is explained in the [Repeater](/bricks/schema/repeater-items) page. - The `BrickStory` type is explained in the [Stories](/bricks/schema/stories) page. ::: ### Properties definition | Property | Definition | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | The unique name for this block type (for example _"hero-unit"_). The "RB_PAGE_EMBED" name is reserved and should be used only for an embed brick. | | `label` | The name displayed in the Sidebar when you want to add a new block (for example _"Hero Unit"_). | | `description` | Optional description for the brick. | | `getDefaultProps` | A function returning the default props for new added blocks. | | `hideFromAddMenu` | If true, the component isn't shown in the list of components available in the "add block" menu. For example, you may want to hide a block that can be used only inside of a [`<Repeater />`](/api-reference/visual-components/repeater). | | `disabled` | If true, the brick is shown as disabled in the editor. | | `disabledIcon` | Optional disabled-state icon: `purchase` or `maintenance`. | | `disabledLink` | Optional URL for more information about the disabled brick. | | `disabledTooltip` | Optional tooltip shown for the disabled brick. | | `sideEditProps` | The array of objects representing the props the user will be able to modify in the right Sidebar, with their display properties. See [Side Edit Props](/bricks/schema/side-edit-props). | | `repeaterItems` | Array to specify behaviour of the bricks used in the `<Repeater>` components. See [Repeater](/api-reference/visual-components/repeater). | | `newItemMenuOpen` | If `true` the "Add new..." accordion menu is open by default; if `false` it is closed by default; otherwise, by default it is open when the number of `repeaterItems` is less than or equal to 4 and closed otherwise. | | `groupByRepeater` | `false` by default. If set to `true` the items that can be repeated are grouped by repeater, using the repeater item `label` as the title of each collapsible section. | | `getExternalData` | Function to fetch external data. It has the page, the brick's props and a third argument as arguments and should return (async) an object which is merged to the brick's props. See [External content](/common-tasks/get-data-from-external-apis/#fetch-external-data-in-a-brick). | | `mapExternalDataToProps` | Function that gets as first argument the external data (from the `getExternalData` function specified on the [pageType](/page-types)) and as second argument the props on this brick. It should return the new props for this brick. See [External content](/common-tasks/get-data-from-external-apis/#fetch-external-data-in-a-brick). | | `playgroundLinkUrl` | Url to link in the Playground, for example to link docs, guidelines, etc. | | `playgroundLinkLabel` | Text for the link in the Playground, for example to link docs, guidelines, etc. | | `category` | Used to categorize bricks. Bricks will be shown grouped by category. | | `tags` | Tags are used to search bricks in the Admin interface. | | `previewImageUrl` | Image URL to be used as preview image for this brick. You can create easily a "screenshot image" of a brick from the Playground. It is shown only if you set the `enablePreviewImage` flag to `true` in the React Bricks configuration. | | `stories` | You may define default stories on a brick. Editors will be able to add their own stories saved on the React Bricks APIs. This feature is available only for "Pro" and upper plans. See [Stories](/common-tasks/reuse-content-across-pages) and the [BrickStory type](/bricks/schema/stories) | | `astroInteractivity` | For Astro projects, controls when the brick hydrates on the client. See [Astro interactivity](/bricks/schema/astro-interactivity/). | # Astro Interactivity > For bricks in an Astro project, specify the type of client interactivity. For a brick inside an Astro project, you can specify the type of client interactivity. By default no JavaScript is sent to the client. For interactive bricks that require client-side JavaScript (such as carousels or forms with validation), you can specify the [Astro client directives](https://docs.astro.build/en/reference/directives-reference/#client-directives) in the brick's schema. To do this, add `astroInteractivity` on the brick's `schema`. This property accepts simple values like `load`, `idle`, `visible`, or objects for more complex scenarios. Here's the TypeScript defintion for `astroInteractivity`: ```ts astroInteractivity?: | 'load' | { load: true } // The same as 'load' | 'idle' | { idle: true } // The same as 'idle' | { idle: { timeout: number } } | 'visible' | { visible: true } // The same as 'visible' | { visible: { rootMargin: string } } | { media: string } | { only: string } ``` ## Usage Examples ```tsx title="Carousel.tsx" {4} ... Carousel.schema = { ... astroInteractivity: 'load' } ``` # Connect external APIs > Connect data from external APIs and use it inside your Bricks, for example to use a headless CMS together with React Bricks visual editing CMS. import Video from '@components/Video' In a brick, you can fetch data from external APIs and make it available on the brick's props. To achieve this, define the `getExternalData` function on the brick's `schema`. This function receives the current page, all the brick's props, and additional arguments that can be passed when calling the `fetchPage` function. It should be an async function that fetches data from external APIs and returns a promise resolving to an object. This object is then merged with the brick's props, making the external API data available for use within the brick. :::note You can fetch external data using values from brick props, page metadata such as the slug, or page custom fields. ::: ## Usage Examples ### Fetch based on a Page custom field ```tsx title="Product.tsx" {5} ... Product.schema = { ... getExternalData: async (page, brickProps) => { const res = await fetch(`https://externalapi/products/${page.customValues.productId}`) const product = await res.json() return ({ productName: product.name productImage: product.imageUrl }) } } ``` ### Fetch based on a brick's prop ```tsx title="StockQuote" {24, 61-77} import { types } from 'react-bricks/rsc' import classNames from 'classnames' interface StockQuoteProps { symbol: string stockResult: { c: number d: number dp: number h: number l: number } } const StockQuote: types.Brick<StockQuoteProps> = ({ symbol, stockResult }) => { if (!stockResult) { return ( <div className="text-center text-red-500 underline text-xl"> Symbol not found! </div> ) } const { c, d, dp, h, l } = stockResult return ( <div className="my-12 w-52 mx-auto rounded-full border px-6 py-3"> <div className="flex items-center justify-between"> <div className="text-black font-bold">{symbol}</div> <div className="text-black font-bold">{c?.toFixed(2)}</div> </div> <div className="flex items-center justify-between"> <div className={classNames( 'text-sm font-bold', dp >= 0 ? 'text-green-500' : 'text-red-500' )} > {dp?.toFixed(2)}% </div> <div> <input type="range" readOnly min={l} max={h} value={c} className="w-24 h-1 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-2 [&::-webkit-slider-thumb]:h-2 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-500" /> </div> </div> </div> ) } StockQuote.schema = { name: 'stock-quote', label: 'Stock Quote', getExternalData: async (page, brickProps) => { const response = await fetch( `https://finnhub.io/api/v1/quote?symbol=${brickProps?.symbol}&token=<Your_FinnHub_Token>`, { next: { revalidate: 10 } } ) const data = await response.json() return { stockResult: { c: data.c, d: data.d, dp: data.dp, l: data.l, h: data.h, }, } as Partial<StockQuoteProps> }, sideEditProps: [ { name: 'symbol', label: 'Symbol', type: types.SideEditPropType.Text, }, ], } export default StockQuote ``` #### Result <Video src="/videos/adv-features/external_data_stock_opt.mp4" /> ## TypeScript signature ```ts getExternalData?: ( page: Page, brickProps?: T, args?: any ) => Promise<Partial<T>> ``` ### Arguments | Property | Definition | | ------------ | -------------------------------------------------------------------------------------------------- | | `page` | The page object for the current page. | | `brickProps` | The props for this brick. The generic type is inherited from the brick's interface. | | `args` | Arguments that can be passed from the `fetchPage`, for example to receive a querystring parameter. | ### Return value A promise resolving to an object of type `Partial<T>`, where T is the brick component's interface. This returned object is merged with the brick's props. ## Use data fetched at Page level If you defined the `getExternalData` on the `pageType`, rather than on the brick's `schema`, you can map the external data fetched at page-level to the brick props using the `mapExternalDataToProps` function. ### Usage example ```ts MyBrick.schema = { ... mapExternalDataToProps: (externalData, bricksProps) => ({ title: externalData.productName, ... }) } ``` ### `mapExternalDataToProps` Signature ```ts mapExternalDataToProps?: (externalData: Props, brickProps?: T) => Partial<T> ``` The function receives: 1. The external data fetched at page level 2. The current brick props The return value should be an object which gets merged with the brick's props. :::tip[Practical how-tos] For guided examples, see [Fetch external data in bricks](https://www.reactbricks.com/how-tos/integrate-external-data/fetch-external-data-in-bricks) and [Fetch external data in page types](https://www.reactbricks.com/how-tos/integrate-external-data/fetch-external-data-in-page-types). ::: # Default Props > Get default props for a brick, applied when an instance of the brick is added to a page. The `getDefaultProps` function defines the default props to be applied when a brick instance is added to a page. It should return an object containing these props. By passing your brick's props to the `types.Brick<T>` generic, you ensure that the object returned by `getDefaultProps` is fully typed. ## Usage Example ```tsx MyBrick.schema = { // ... getDefaultProps: () => ({ imageSide: 'right', title: 'This is the default title', faqs: [ { question: 'Which came first, the chicken or the egg?', answer: "It depends on how you define a chicken's egg. At some point in evolutionary history when there were no chickens yet, two birds that were almost-but-not-quite chickens mated and laid an egg that hatched into the first chicken. If a chicken's egg is defined as 'an egg laid by a chicken', then the chicken came first; if it is defined as 'an egg that a chicken hatches from', then the egg came first.", }, ], }), } ``` # Repeater Items > In React Bricks you can infinitely nest bricks. Here's how you define Repeater Items in the brick's schema. When you need to repeat bricks inside another brick, creating a nested structure, you use a [`Repeater` component](/api-reference/visual-components/repeater). To let React Bricks know which brick (or bricks) should be repeated inside a Repeater, add the `repeaterItems` array to the brick's `schema`. ## Usage Example ```ts {3-10} MyBrick.schema = { ... repeaterItems: [ { name: 'socialProof', itemType: 'customer-logo', itemLabel: 'Logo', max: 12, }, ], } ``` ## Properties Here's the TypeScript interface for `repeaterItems`: ```ts repeaterItems?: IRepeaterItem[] ``` Where `IRepeaterItem` is defined as: ```ts interface IRepeaterItem<T = any> { name: string label?: string itemType?: string itemLabel?: string defaultOpen?: boolean min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean items?: { type: string label?: string min?: number max?: number getDefaultProps?: () => Props show?: (props: T, page?: Page, user?: User) => boolean }[] } ``` ### Properties Definition | Property | Definition | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Name of the prop containing the repeated items (e.g., "buttons") | | `itemType` | Corresponds to the unique `name` of the repeated Brick type (e.g., "my-button") | | `label?` | Label for the group of items in this repeater (title of nested items) | | `itemLabel?` | Optional label for Add / Remove buttons. If not provided, the repeated brick's label is used as a fallback | | `min` | Minimum number of repeated items allowed. React Bricks ensures at least this number of blocks (adding items with default values) | | `max` | Maximum number of repeated items allowed. When reached, no more blocks can be added to the repeater | | `getDefaultProps` | Function returning default props for the repeated bricks. For example, for a Button brick repeated inside a Form brick, you could specify that the default type should be "submit" instead of "link". | | `show` | Optional function to conditionally show the repeater item based on the current props, page and user. | | `items` | Allowed item types, when multiple. In this case the main `itemType` and `min` are ignored. Each item has its own `type`, `label`, `min`, `max`, `getDefaultProps` and `show`. | ### Multiple item types - `itemType` is used for a single type of brick that can be repeated in a Repeater (e.g. a Thumbnail in a Gallery). - `items` is used for multiple types of brick in a Reapear (e.g., in a Form you may add "TextInput" blocks or "Select" blocks). - With multiple item types, each with its own `min` and `max`, the root item's `min` is ignored, while the overall `max` is still enforced. # Sidebar controls > React Bricks sideEditProps let you define sidebar controls that content editors use to set properties for a brick. Sidebar controls offer content editors controlled flexibility by allowing them to set properties for a brick. These properties are typically used in the component's JSX to apply CSS rules conditionally. This enables editors to modify elements like background color, title size, or padding values. ## `sideEditProps` Sidebar controls are defined in the `schema`'s `sideEditProps` property. This property contains an array of sidebar controls. When there are many controls, it can also include an array of collapsible groups for better organization. Each group contains its own array of controls. Each "sideEditProp" has: - A `name` that matches the prop set on the React component - A `label` for the user interface - A `type` that defines the type of control that the content editors will use to set the corresponding prop (e.g., select, text, range) - Optional helper text, validation rules and conditional rendering - Additional properties specific to the control type ## Usage Example ```tsx MyBrick.schema = { ... sideEditProps: [ { name: 'withImage', label: 'With Image', type: types.SideEditPropType.Boolean, }, { name: 'imageSide', label: 'Image Side', type: types.SideEditPropType.Select, selectOptions: { display: types.OptionsDisplay.Radio, options: [ { value: 'left', label: 'Left' }, { value: 'right', label: 'Right' }, ], }, // Show only if `withImage` is true show: (props) => props.withImage }, { name: 'url', label: 'Url', type: types.SideEditPropType.Text, // Validate URL validate: (value) => value.startsWith('https://') || 'Invalid URL' }, ], ... } ``` ## Properties Here is the Typescript interface for each side-edit prop: ```ts interface ISideEditProp { name: string label: string type: SideEditPropType component?: React.FC<ICustomKnobProps> validate?: (value: any, props?: Props) => boolean | string show?: (props: Props, page?: Page, user?: User) => boolean helperText?: string shouldRefreshStyles?: boolean textareaOptions?: { height?: number } imageOptions?: { maxWidth?: number quality?: number // default 80 aspectRatio?: number } rangeOptions?: { min?: number max?: number step?: number } selectOptions?: { options?: IOption[] getOptions?: (props: Props) => IOption[] | Promise<IOption[]> display: OptionsDisplay } autocompleteOptions?: { getOptions: (input: string, props: Props) => any[] | Promise<any[]> getKey: (option: any) => string | number getLabel: (option: any) => string renderOption?: ({ option, selected, focus, }: { option: any selected: boolean focus: boolean }) => React.ReactElement placeholder?: string debounceTime?: number getNoOptionsMessage?: (input?: string) => string } iconSelectorOptions?: { iconSets?: IconSets[] } relationshipOptions?: { label?: string references: string multiple: boolean embedValues?: boolean } onChange?: (props: Props) => Partial<Props> } ``` Where `SideEditPropType` is defined as follows: ```ts enum SideEditPropType { Text = 'TEXT', Textarea = 'TEXTAREA', Number = 'NUMBER', Date = 'DATE', Range = 'RANGE', Boolean = 'BOOLEAN', Select = 'SELECT', Autocomplete = 'AUTOCOMPLETE', Image = 'IMAGE', Custom = 'CUSTOM', Relationship = 'RELATIONSHIP', IconSelector = 'ICON-SELECTOR', } ``` and `IconSets` is defined as follows: ```ts enum IconSets { Lucide = 'lu', HeroIconSolid = 'hi-solid', HeroIconOutline = 'hi-outline', FontAwesome = 'fa6', Feather = 'fi', } ``` ## Properties definition | Property | Definition | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | The name of the prop passed to the component. | | `label` | The label displayed in the edit sidebar. | | `type` | One of the following:`SideEditPropType.Text`, `SideEditPropType.Number`, `SideEditPropType.Date`, `SideEditPropType.Range`, `SideEditPropType.Boolean`, `SideEditPropType.Select`, `SideEditPropType.Autocomplete`, `SideEditPropType.Image`, `SideEditPropType.Custom` (see [SideEditPropType](/api-reference/types-reference/enums#sideeditproptype)).<br /><br />The `IMAGE` type is useful for images edited in the sidebar, like background images.<br /><br />The `CUSTOM` type allows you to provide your own sidebar component. | | `component` | Optional. Required for `SideEditPropType.Custom` type. Provide a custom React functional component with props `value`, `onChange`, and `isValid` to edit this prop. | | `validate` | Validation function that receives the value as the first argument and all props as the second argument (object with key-value pairs). It should return `true` for valid, `false` for invalid, or a string for an invalid state with an error message. | | `show` | Function that determines whether to display the editing control. It receives props, current page, and logged-in user. Useful for conditional display based on other props or user roles. | | `shouldRefreshStyles` | Set totrueif changing this value could trigger new style injections by a CSS-in-JS library, ensuring correct loading of new styles. | | `helperText` | Optional text diplayed below the control to guide the user. | | `textareaOptions` | Specify the `height` for a textarea field. | | `imageOptions` | For `SideEditPropType.Image` props, specify the `maxWidth` (the optimization algorithm uses 2x this for retina displays) and desired `aspectRatio` for cropping. | | `rangeOptions` | For `SideEditPropType.Number` and `SideEditPropType.Range` props, specify the `min`, `max` and `step` values. | | `selectOptions` | For `SideEditPropType.Select` props, specify:<br /><br />1. `options`: Array of options with `value` (passed to the React component) and `label` (shown in the Sidebar).<br />See the [IOption](/api-reference/types-reference/interfaces#ioption) interface.<br /><br />2. `getOptions`: function returning options or a promise resolving to options. It receives the brick current props. Use for dynamic options, for example from API calls. Alternative to `options`<br /><br />3. `display`: one of `types.OptionsDisplay.Select` (dropdown), `types.OptionsDisplay.Radio` (radio buttons), or `types.OptionsDisplay.Color` (colored circles). For colors, the value should be an object with a `color` prop, and any other needed props.<br />See [OptionsDisplay](/api-reference/types-reference/enums#optionsdisplay) | | `autocompleteOptions` | For `SideEditPropType.Autocomplete` props, specify:<br /><br />1. `getOptions`: Async function receiving search input and brick props, returning an array of option objects.<br /><br />2. `getKey`: Function returning a unique key for an option object<br /><br />3. `getLabel`: Function returning the label for an option in the dropdown and for the selected option.<br /><br />4. `renderOption`: Function returning JSX for the dropdown menu, overriding `getLabel` for the dropdown menu (`getLabel` is still used to display the selected option)<br /><br />5. `placeholder`: Input placeholder text<br /><br />6. `debounceTime`: debounce time for the async function in milliseconds (default: 350ms).<br /><br />7. `getNoOptionsMessage`: Function receiving the input value, returning a message when no options are found. | | `iconSelectorOptions` | For `SideEditPropType.IconSelector` props, optional. Specify an array of `iconSets` that should be returned in the search results, where the values are of type [IconSets](/api-reference/types-reference/enums#iconsets). If not provided, all icon sets are available. | | `relationshipOptions` | For `SideEditPropType.Relationship` props, specify:<br /><br />1. `label`: The label.<br /><br />2. `references`: Name of the referenced `pageType` (e.g., "category" for a product).<br /><br />3. `multiple`: If `true`, allows multiple selections (many-to-many); if `false`, single selection (one-to-many).<br /><br />4. `embedValues`: If `true`, includes all values for the related entity in a prop named `{name}_embed`; default is `false` (only ID of related entity). | ## Validation You can validate user input for each sidebar control by providing a `validate` function This function receives two arguments: the control's value and an object containing all props. It should return one of the following: - `true`: The value is valid - `false`: The value is invalid. No error message is provided, but the control will display a red border to indicate the error. - A string: the value is invalid. The value is invalid. The string serves as an error message displayed to the user. ### Preventing Saves with Validation Errors When any brick control on the page has a validation error, a tooltip appears on the "Save" button. This tooltip informs the editor that at least one error exists. To enhance error prevention, you can set the `disableSaveIfInvalidProps` property to true in the [React Bricks configuration](/common-tasks/customize-react-bricks/). This setting prevents saving if any errors are present on the page. ## Conditional rendering of controls You can conditionally display a sidebar control by providing a `show` function. This function receives props, the current page, and the logged-in user as arguments. This feature is useful for showing controls based on other controls' values (e.g., displaying an image side prop only when an image exists) or user properties (such as hiding a control for specific users or roles). ## Collapsible groups Sidebar controls can be organized into collapsible groups for better organization. A collapsible group is defined by this interface: ```ts interface ISideGroup<T = Props> { groupName: string defaultOpen?: boolean show?: (props: T, page?: Page, user?: User) => boolean props: ISideEditProp<T>[] | ISideEditPropPage<T>[] } ``` The interface properties are: - `groupName`: The group's label. Clicking it toggles the expansion of the control group. - `defaultOpen`: Specifies whether the group is initially expanded (defaults to false). - `show`: A function determining the group's visibility based on component props, the current page and the logged-in user. - `props`: An array of `ISideEditProp` objects defining the group's controls. :::tip[Practical how-tos] For task-oriented examples, see [Add a sidebar control](https://www.reactbricks.com/how-tos/create-a-brick/add-a-sidebar-control), [Use simple sidebar controls](https://www.reactbricks.com/how-tos/sidebar-controls-in-depth/use-simple-sidebar-controls), [Use the Select control](https://www.reactbricks.com/how-tos/sidebar-controls-in-depth/use-the-select-control), and [Organize controls in groups](https://www.reactbricks.com/how-tos/sidebar-controls-in-depth/organize-controls-in-groups). ::: ## Control types Let's examine each type of available control in more detail. ### Simple types Some simple types require no additional configuration. These include `Text`, `Date`, and `Boolean`. ### Select Use this control type when you want content editors to choose one value from multiple options. You can present the options as a drop-down menu, a set of radio buttons, or multiple colored circles for color selection. Values can be provided statically with options or dynamically through an async function call (getOptions) that resolves to the options array. To configure the select control, use the `selectOptions` object with the following properties: 1. `options`: An array of options, each with a value (passed to the React component) and a label (displayed in the Sidebar). Refer to the [IOption](/api-reference/types-reference/interfaces#ioption) interface for details. 2. `getOptions`: A function that returns options or a promise resolving to options. It receives the brick's current props. Use this for dynamic options, such as those from API calls. This is an alternative to `options`. 3. `display`: Choose from `types.OptionsDisplay.Select` (dropdown), `types.OptionsDisplay.Radio` (radio buttons), or `types.OptionsDisplay.Color` (colored circles). For colors, the value should be an object with a color prop and any other necessary props. See [OptionsDisplay](/api-reference/types-reference/enums#optionsdisplay) for more information. ### Autocomplete Use this control type when you want content editors to choose one value from multiple options returned by an async function call to external APIs. The options depend on the user's input, providing search-like functionality. To configure the autocomplete control, use the `autocompleteOptions` object with the following properties: 1. `getOptions`: An async function that receives search input and brick props, returning an array of option objects. 2. `getKey`: A function returning a unique key for an option object. 3. `getLabel`: A function returning the label for an option in the dropdown and for the selected option. 4. `renderOption`: A function returning JSX for the dropdown menu items, overriding getLabel for the menu (note: getLabel is still used to display the selected option). 5. `placeholder`: The input placeholder text. 6. `debounceTime`: The debounce time for the async function in milliseconds (default: 350ms). 7. `getNoOptionsMessage`: A function receiving the input value and returning a message when no options are found for the current input. ### Image Use this control type for images that can't be edited visually by clicking on the content, such as background images. To configure the image control, use the `imageOptions` object with the following properties: 1. `maxWidth`: The optimization algorithm uses twice this width as the maximum dimension for retina displays. 2. `aspectRatio`: Sets a fixed aspect ratio for cropping (e.g. `16 / 9`). ### Number and Range For Number and Range controls, you can specify `rangeOptions`. This object allows you to set the `min` (minimum), `max` (maximum), and `step` values. These parameters define the control's range and increment. ### Textarea For Textarea controls, you can specify `textareaOptions`. This object has a single property, `height`, which allows you to set the desired height for the field. ### Icon Selector Content editors often need to choose an icon from a set, searching by keywords. The IconSelector control type is ideal for this scenario. It provides an autocomplete control that connects to our advanced icon search service, allowing semantic searches for icons from popular libraries such as HeroIcons, Feather icons, and FontAwesome. In the `iconSelectorOptions`, you can specify `iconSets`, an array of [`types.IconSets`](/api-reference/types-reference/enums#iconsets) that should be available in the search results. If not specified, all icon sets will be available. The prop value is of type [`types.Icon`](/api-reference/types-reference/types#icon). Pass it to the [Icon component](/api-reference/visual-components/icon) to render an inline SVG that allows customizing props like width, height, and className. ### Relationship Use this control when you want editors to choose a page of a specific pageType, establishing a relationship between the current brick and a page or entity. This is particularly useful when you need to render custom field values of a related entity (for instance, the name of a product's related category). In the `relationshipOptions`, specify: 1. `label`: The label for the select control 2. `references`: Name of the referenced `pageType` (e.g., "category" for a product). 3. `multiple`: Set to `true` for multiple selections (many-to-many), or `false` for single selection (one-to-many). 4. `embedValues`: When `true`, includes all values for the related entity in a prop named `{name}_embed`. Defaults to `false`, providing only the ID of the related entity. ## Custom Components You can provide your own editing component for a `sideEditProp` (for example, a small map for latitude and longitude selection). In this case, set the `type` of control to `types.sideEditPropType.Custom`. Provide your own React functional component in the `component` property. This component will receive the following props: - `value`: The current value of the prop. - `onChange`: A function that accepts a new value as an argument to update the prop. - `isValid`: A boolean indicating whether the prop matches the validation rules, allowing you to apply styles for invalid states. # Stories > React Bricks stories offer a way to re-use a particular brick configuration. import Video from '@components/Video' Stories, along with [Embed](/common-tasks/reuse-content-across-pages/), offer a way to [re-use content across pages](/common-tasks/reuse-content-across-pages/). While embedding a page within another provides a "single source of truth" (changes to an embedded page affect all pages embedding it), a "story" acts more like a template for bricks. A story is a named set of props for a brick. When you apply a story to a brick, you're applying these saved props. After application, the brick can be modified independently, without maintaining any connection to its original story. ## How to create a story Stories can be created in two ways: - **From the editor**: Using the "Stories" tab when a block is selected. These stories are saved to the React Bricks database and retrieved via APIs by the editor interface. - **In code**: By the developer, using the `stories` array in the [brick's schema](/bricks/schema/). These stories reside in your design system's code. ## Stories saved from the Editor interface Here's' how content editors can save stories for a brick from the editor interface: <Video src="/videos/adv-features/stories.mp4" /> ## Stories set in code In the brick's `schema`, you can define an array of stories using the `stories` property. You can also specify whether a story appears as a normal brick in the "Add new brick" menu by setting the story's `showAsBrick` flag to `true`. ### Example usage ```ts HeroUnit.schema = { ... stories: [ { id: 'black-friday-cta', name: 'CTA for Black Friday', props: { title: 'Black friday discount', background: { color: '#000', className: 'bg-black' } }, showAsBrick: true }, ], } ``` ### Properties Each element has the following TypeScript interface (the generic type is inherited from the brick's component interface): ```ts type BrickStory<T = Props> = { id: string name: string showAsBrick?: boolean previewImageUrl?: string disabled?: boolean disabledIcon?: 'purchase' | 'maintenance' disabledLink?: string disabledTooltip?: string props: T } ``` ### Properties definition | Property | Definition | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `id` | Unique identifier for this story. | | `name` | Name for the story displayed in the editor. | | `showAsBrick` | If `true`, the story appears as a new brick in the "Add new brick" interface, making it directly selectable. Default: `false`. | | `previewImageUrl` | Preview image for this story (required only if `showAsBrick` is true). | | `disabled` | If `true`, the story is shown as disabled in the editor. | | `disabledIcon` | Optional disabled-state icon: `purchase` or `maintenance`. | | `disabledLink` | Optional URL for more information about the disabled story. | | `disabledTooltip` | Optional tooltip shown for the disabled story. | | `props` | The object containing the props to be applied by this story. | # Visual Editing > Bricks use the React Bricks visual editing components to enable inline visual editing. import { CardGrid, LinkCard, Steps } from '@astrojs/starlight/components' Visual Editing is one of React Bricks' strongest unique selling propositions. In your Bricks, you can use React Bricks' Visual Editing components to enable inline editing of text and images directly on the content, eliminating the need for a cumbersome preview system. React Bricks also allows for infinite nesting of bricks within bricks, enabling the creation of galleries, features, buttons in hero units, or pricing pages. ## Visual components The following are the visual editing components. Each has a dedicated page in the subsequent sections of the documentation: <CardGrid> <LinkCard title="Text" description="For editable plain text. Provide a render function to render your JSX." href="/api-reference/visual-components/text" /> <LinkCard title="RichText" description="For editable rich text. Choose the allowed rich-text capabilities and override the default render functions." href="/api-reference/visual-components/rich-text" /> <LinkCard title="Image" description="For editable images. Select from the Media Library, upload, use Unsplash, or input a URL. Crop, rotate, or flip images. Images are optimized and served from a CDN." href="/api-reference/visual-components/image" /> <LinkCard title="Repeater" description="To repeat multiple nested items, such as images in a gallery. Allows for infinite nesting of bricks and multiple item types per repeater." href="/api-reference/visual-components/repeater" /> <LinkCard title="Link" description="Simplifies link management for standalone links or within RichText render functions. It uses the framework's link component for local paths." href="/api-reference/visual-components/link" /> <LinkCard title="File" description="Enables editors to upload files and provides a render function for frontend downloads. Files are served from a global CDN." href="/api-reference/visual-components/file" /> <LinkCard title="RichTextExt" description="An extensible RichText component that allows for the creation of custom RichText plugins for advanced use cases." href="/api-reference/visual-components/rich-text-ext" /> </CardGrid> # A/B Testing and Multischeduling > Create content variants, schedule each variant independently, and run A/B tests when multiple variants are active. React Bricks v5 introduces variants for pages. Variants can be used for multischeduling and A/B testing. With variants, you can prepare multiple versions of the same page and decide when each one should be active. When more than one variant is active at the same time, React Bricks can serve them according to the weights you configure. ## Multischeduling Multischeduling lets you create variants and set scheduled publish and unpublish dates for each variant. This is useful when a page needs to change across a campaign timeline, for example: - a teaser before a launch - a launch-day version - a post-launch version - a seasonal promotion with a fixed end date Each variant has its own scheduling window, so editors can prepare the full sequence in advance. ## A/B Testing A/B testing uses the same variant system. For each active variant, you can set a weight. When multiple variants are active at the same time, React Bricks serves them according to those weights. For example: | Variant | Weight | | ------- | ------ | | A | 50 | | B | 50 | This creates an even split. A `70 / 30` split can be configured by setting the weights accordingly. ## Middleware helpers React Bricks provides middleware helpers to resolve the active variant for a request: - [`createAbTestingMiddleware`](/api-reference/utilities/create-ab-testing-middleware/) for Next.js Pages and Astro - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) for Next.js App when you need to chain A/B testing with the i18n middleware The starter projects include examples on the `ab-testing` branch, including middleware setup and analytics integration: see [https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps](https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps) ## Analytics The `ab-testing` branch of the starter projects has an [implementation example](https://github.com/ReactBricks/reactbricks-starters/blob/03ea4d534b518ab4ec0598624f97dd6b574a09ae/apps/nextjs-app/app/%5Blang%5D/%5B%5B...slug%5D%5D/page.tsx#L139) showing how to send the test name and variant name to Google Analytics. ## Developer setup For the code-focused setup path, see [Implement A/B Testing](/common-tasks/implement-ab-testing/). # Approval Workflow > With React Bricks you can decouple saving and committing on a page and activate a full approval workflow. import Video from '@components/Video' In React Bricks, you have the option to activate two different types of workflows for pages: 1. **Working Copy**: This workflow decouples saving and publishing. Content becomes visible only when marked as ready for publishing. 2. **Approval**: In this workflow, once the editor commits the content, a user with appropriate permissions must approve it before it becomes visible. ## Working Copy ![components-structure-frontend](/images/working_copy.svg) With the "Working Copy" workflow, saved content isn't immediately available. This means that a saved page under construction won't appear on the production website when someone requests a static site rebuild or views it with server-side rendering (SSR). Saving a page creates a new "working copy" of the content. Once the page is ready, you can "commit" the changes to make them available for deployment. ## Approval Workflow ![components-structure-frontend](/images/approval_workflow.svg) The approval workflow builds on the Working Copy workflow by adding an extra step. When an editor commits a page's content, the working copy doesn't immediately merge into production. Instead, another user with approval permissions must review and approve the content before it can be merged into the production environment. If you have the Approval Workflow add-on enabled, you can configure this workflow from the Dashboard. <Video src="/videos/dashboard/approval_workflow.mp4" /> # Backup and Restore > With React Bricks you can always request a backup and restore of your content and also schedule full backups to an off-site S3 storage. import Video from '@components/Video' This interface allows you to request a complete backup of your content in JSON format. Once the backup is ready, you'll receive an email with a download link. <Video src="/videos/dashboard/backup.mp4" /> To download all images as well, you'll need to parse the JSON files and fetch images from their URLs. ### Scheduled Backup Enterprise customers can enable Scheduled Backup, which creates a daily or weekly off-site copy of all content and assets to their S3-compatible storage. # Collaboration > React Bricks CMS has real-time collaboration based on real-time presence and page lock. import Video from '@components/Video' The collaboration feature combines real-time presence and page locking. <Video src="/videos/admin_interface/collaboration.mp4" /> ## Real-time presence - The header displays avatars of users currently logged into the app. - On each page, you can see who's viewing it. A pink border indicates the user who has locked the page (the first to start editing). ## Page lock - The first user to start editing a page acquires the lock, preventing others from editing until it's released. - The page unlocks when the user who locked it saves their changes or leaves without saving, allowing others to edit. - For urgent changes to a locked page, you can use the "Force unlock" button in the right sidebar. This gives you control but discards any unsaved changes from the previous editor, so use sparingly. # Content versioning > The React Bricks change history lets you view a list of changes for any page and revert to a previous status. import Video from '@components/Video' Change History allows users to view a list of modifications made to any page. For each change, users can see the page's status before the modification, compare the differences and revert to the previous status. The duration for which this history is retained depends on the app's subscription plan. <Video src="/videos/dashboard/history.mp4" /> Users can easily filter changes by the person who performed a specific action or by the affected page. Content editors can also access each page's change history directly from the editor by clicking the "Change history" button in the right sidebar. # DAM (Digital Assets Manager) > React Bricks Media Library is a complete DAM (Digital Assets Manager) to store, organize, transform and reuse assets import Video from '@components/Video' React Bricks' Media Library houses all images and files uploaded to a project. Images can be viewed in a thumbnail layout (with adjustable size) or as a list. Users can search media using the search bar or filters, and can select items to move to the trash bin—from which they can be permanently deleted or restored. The Media Library also allows for folder creation to better organize assets. <Video src="/videos/admin_interface/media_organization_opt.mp4" /> Images can be loaded into the project from various sources: - [Upload](#upload) - [Media Library](#from-media-library) - [Unsplash](#from-unsplash) - [URL](#from-url) ## Upload Clicking on an image will open the window where it can be edited or replaced. Clicking the button "Replace image" and choosing the option "Upload" will open another window in which the image can be uploaded by selecting it from a folder or by dragging and dropping it in the grey area. Once the image is uploaded, it will be possible to see its details and to change some of its properties such as: file name, title/caption, alternate text, source and copyright. The image is now ready to be flipped, rotated or cropped or just added to the page as it is. <Video src="/videos/admin_interface/media_load_upload_opt.mp4" /> ## From Media Library To replace an image from the Media Library, click the image, select "Replace image," and choose "from Library." This opens React Bricks' Media Library window, where you can find media using the search bar, filters, or by browsing folders (which can be created in the Media page). If the chosen media is already used in other pages, you can select one of those versions. After selection, you can modify properties like alternate text and SEO-friendly name. The image is then ready for flipping, rotating, cropping, or direct addition to the page. <Video src="/videos/admin_interface/media_load_library_opt.mp4" /> ## From Unsplash To use an Unsplash image, click the image, select "Replace image," and choose "from Unsplash." This opens a window where you can search for and select an image. Once selected, the image is added to the Media Library. You can then view its details and modify properties such as file name, title/caption, alternate text, source, and copyright. The image is ready for flipping, rotating, cropping, or direct addition to the page. <Video src="/videos/admin_interface/media_load_unsplash_opt.mp4" /> ## From URL To use an image from a URL, click the image, select "Replace image," and choose "from URL." Enter the new image URL in the window that appears. After the image loads, you can view its details and modify properties such as file name, title/caption, alternate text, source, and copyright. The image is then ready for flipping, rotating, cropping, or direct addition to the page. <Video src="/videos/admin_interface/media_load_url_opt.mp4" /> ## Batch upload React Bricks' Media Library supports both individual and batch uploads. Click "Upload images" to open a window where you can select multiple images from a folder or drag and drop them into the designated area. Once the upload is complete, the images will be available in the library. <Video src="/videos/admin_interface/media_batch_upload_opt.mp4" /> ## Image editing After selecting an image, you can flip, rotate, or crop it. <Video src="/videos/admin_interface/media_editing_opt.mp4" /> # Email Marketing > Create email marketing pages in React Bricks and send or schedule campaigns through supported Email Sending Providers. React Bricks v5 adds email marketing support, so teams can create email campaigns with the same visual editing model used for website pages. Email marketing pages are identified by a dedicated page type and can be connected to an Email Sending Provider from the dashboard. ![React Bricks Email Marketing provider configuration](/images/cms-features/email-marketing-providers.png) ## Supported providers Supported Email Sending Providers include: - MailChimp - Brevo - Mailerlite - GetResponse - SendGrid - Resend - ConvertKit ## Email marketing page types Email campaigns are created from page types marked as email marketing page types. The page type fields for email marketing are documented in [Page Types](/page-types/#email-marketing-page-types). For the code-focused setup path, see [Implement Email Marketing](/common-tasks/implement-email-marketing/). ## Campaign options Pages with `isEmailMarketing: true` include campaign-specific options in the editor. ![React Bricks email marketing editor interface](/images/cms-features/email-marketing-editor.png) Editors can select: - an Email Sending Provider - a list - a sender - a campaign name They can also send a test, send the campaign, or schedule it. ## Email bricks The starter projects include optional email marketing bricks based on `react-email`. These bricks can be installed by the CLI and used as a starting point for your own email design system. ## Developer setup Developers configure email marketing page types and email-specific bricks in code. See [Implement Email Marketing](/common-tasks/implement-email-marketing/) for the implementation path and [IPageType](/api-reference/types-reference/interfaces/#ipagetype) for the type reference. # Form Management > Create forms from the dashboard and submit data from form bricks. React Bricks v5 adds form management. You can create forms from the dashboard and decide what should happen when a visitor submits a form. ![React Bricks Forms dashboard](/images/cms-features/form-management-list.png) ## Form actions Forms can be configured with one or more actions: - save submitted data - send an email with the submitted data - subscribe the visitor to an Email Sending Provider list - call a Zapier webhook This lets teams manage common website forms without hard-coding every workflow in the frontend. ![React Bricks form actions configuration](/images/cms-features/form-management-edit.png) ## Submitting form data Use the [`sendFormSubmission`](/api-reference/utilities/send-form-submission/) function from a form brick to submit data to a React Bricks form. The form brick owns the frontend markup and validation experience, while React Bricks handles the configured form actions. If you want the content team to create forms directly in the frontend, you can start from the [example Form Builder bricks](https://github.com/ReactBricks/reactbricks-internal/tree/main/packages/reactbricks-ui/nextjs-app/src/contacts/FormBuilder). They provide a composable set of form bricks, so editors can assemble fields visually while React Bricks still manages submissions and backend actions. In practice, a form brick usually: 1. Renders the form fields. 2. Collects the submitted values. 3. Calls `sendFormSubmission` with the app data, token, form identifier, submitter email address, submitted data, and fetch options. 4. Shows a success or error state to the visitor. The exact fields depend on the form you configured in the dashboard. For the TypeScript signature, see [`sendFormSubmission`](/api-reference/utilities/send-form-submission/). ## Spam protection React Bricks forms support Google reCAPTCHA v3 protection. Use reCAPTCHA for public forms where you need protection against automated submissions. For reCAPTCHA spam prevention to work, provide the **Form reCAPTCHA V3 secret** in the React Bricks Dashboard, under **App Settings**. ![Form reCAPTCHA V3 secret setting in the React Bricks Dashboard](/images/cms-features/form-management-recaptcha-secret.png) ## Developer setup For the code-focused setup path, see [Submit Forms](/common-tasks/submit-forms/). # Image Optimization and CDN > React Bricks optimizes your images at upload time and serves them from a global CDN. React Bricks optimizes your images at upload time and serves them from a global CDN. This eliminates long build times and the need for external services. ## Why is it Important? Images significantly affect a website's performance as they are a heavy asset that can slow down page loading times. Optimizing them for responsive views and asynchronous loading can be challenging. This is why frameworks such as Next.js and Astro provide image tooling to optimize image loading. ## How Optimization Works React Bricks handles all necessary image optimizations, eliminating the need for external services. ### Responsive images Serving large images to mobile devices wastes network resources, especially considering that such devices often have unreliable internet connections. React Bricks creates responsive images for various screen sizes. Its `<Image>` component, with the source-set attribute, delivers the most suitable image for any device size. This optimizes the use of high-resolution displays and prevents unnecessary transmission of large images to mobile devices. ### Lazy Loading Loading images that are below the fold (the unseen portion of the screen) unnecessarily increases the page's time-to-last-byte (TTLB), as it loads content that isn't immediately visible. React Bricks leverages the browser native lazy load feature when available. If not, it creates a very small blur-up image that is replaced with the actual image once it enters the visible viewport. ### Content Delivery Network By bringing content closer to your users worldwide, you can significantly improve the download speed of assets. React Bricks uses a fast global CDN to deliver your images, ensuring quick loading times for all users. This feature is free and included in all plans. Additionally, you have the option to use a custom domain for your CDN assets. ## No more long build times If you have a large website with many images and use Static Site Generation, you know that building the website can become a lengthy process. React Bricks offers a solution. All image optimizations happen on our servers at upload time (using an async queue). There's no need to wait for images to optimize at build time—they're already at the edge, ready to be served! ## A cross-platform solution When you start using framework-specific image tooling, you need to learn how it works and the potential pitfalls with some CSS layouts. When you switch platforms, you'll need to re-implement everything from scratch. The `<Image>` component in React Bricks is cross-platform. Your bricks will function seamlessly on Next.js or Astro without changing a line of code. # Localization > Manage translated React Bricks content across languages from the CMS. import Video from '@components/Video' React Bricks has built-in content localization. You can add new languages in the Dashboard (accessible from the Settings tab), based on your plan's limit. Then, you can translate content using the translation tabs in the Page Editor. With multiple locales, the React Bricks interface allows content translation for each page in any locale. <Video src="/videos/internationalization/introduction.mp4" /> ## Settings You can **add / remove languages** and set the **default language** at any time from the Settings tab. <Video src="/videos/admin_interface/i18n_settings.mp4" /> ## Default language The default language serves as **a default and fallback**. For instance, page names on the left sidebar are shown in the default language if available. It is also the language used to copy content from, when a new translation is created. ## Translate pages To translate a page, click on the corresponding **language tab in the Editor**. **If a translation doesn't exist yet**, React Bricks will ask whether you want to create one. <Video src="/videos/admin_interface/i18n_translate.mp4" /> When creating a new translation, **the content is copied from the default language**. If there is no translation for the default language, React Bricks will copy the content from the first available language. **Each translation is independent**, with its own content, page attributes, SEO/meta, and custom field values. ## Delete a translation When you have more than one translation, you can delete a translation. <Video src="/videos/admin_interface/i18n_delete.mp4" /> **Deleting a translation only removes content in that language**, not the entire page. You can't delete the last remaining translation of a page: to remove it, you must delete the whole page. ## Developer setup For localized content fetching, language switchers and i18n routing, see [Localization](/common-tasks/localization/) in Common Tasks. # Multiple Environments > With React Bricks you can create multiple content environments, which are like content branches. import Video from '@components/Video' Environments are like Content branches: separate repositories that keep content for different environments isolated. You can create them from the [React Bricks Dashboard](https://dashboard.reactbricks.com). Environments can be useful in scenarios such as: - Creating a development environment where developers can experiment with content while building new bricks. You can then sync the main environment's content back to the development one when needed. - Working on a v2 of your website while maintaining v1. When ready, you can push the content to the main branch. - Maintaining a backup of an older version of the website content for future use (e.g., creating a branch for Black Friday promotions, then easily reverting to the "normal" content). Each environment has its own content, users, build hooks, languages, and change history. ## How to Use Environments 1. Create and manage environments from the Dashboard 2. Use the `environment` property on the [React Bricks configuration](/common-tasks/customize-react-bricks/) to select the working environment for a project. <Video src="/videos/dashboard/environments.mp4" /> ## Creating a new Environment - When you create a new environment, it inherits all content and configuration from the "main" environment. - You can then modify both the content and other properties of the new environment (e.g., removing existing users or inviting new ones). ## Sync and Push Operations - The "sync" operation updates an environment with the main environment's content, overwriting the environment's content. - The "push" operation transfers an environment's content to the main environment, overwriting the main environment's content. # Users, Roles, Permissions > React Bricks CMS has fine grained roles and permissions. import Video from '@components/Video' Through the Users interface, the app owner and admins can view users and their roles, as well as invite other users to collaborate on the app's content. <Video src="/videos/dashboard/users.mp4" /> For each invited user, it is possible to assign a main role (Admin or Editor), any custom role, and—for editors—enable specific permissions. ## Default User Roles React Bricks offers 3 basic user roles for an app, which can be extended using Custom Roles and Permissions: - **Owner**: Has full control over their apps - **Admin**: Can perform most tasks, except managing the app Plan, Environments, and deleting the app - **Editor**: Can edit page content and, depending on permissions set in the Dashboard, may edit page metadata, create/delete pages, trigger deploys, or approve pages ## Default Permissions | Permission | Owner | Admin | User | | ------------------------------------------------- | ----- | ----- | ---- | | Edit Pages | x | x | x | | Edit SEO | x | x | o | | Edit Page Attributes | x | x | o | | Create Pages | x | x | o | | Delete Pages | x | x | o | | Trigger Dev Deploy Hook | x | x | o | | Trigger Staging Deploy Hook | x | x | o | | Trigger Production Deploy Hook | x | x | o | | Approve content | x | x | o | | Lock / Unlock Pages and Blocks | x | x | | | Edit App Settings | x | x | | | Manage Users | x | x | | | Add / Remove Languages | x | x | | | Manage Build Hooks | x | x | | | See the app Usage | x | x | | | Manage SSO configuration | x | x | | | Manage Approval workflows | x | x | | | Manage the change history | x | x | | | Backup and restore content | x | x | | | Manage off-site backups | x | x | | | Manage the App Plan subscription | x | | | | Manage multiple environments | x | | | | Login without SSO even when "Force SSO" is active | x | | | | Delete the App | x | | | See also [Set Custom Permissions](/common-tasks/custom-permissions/). # Scheduled Publishing > React Bricks offers a built-in scheduled publishing feature, also triggering a build hook when future-dated content is published. Marketing teams often prepare content in advance and schedule it for future publishing. This practice applies to various types of content, including blog posts, seasonal greetings, and e-commerce discounts. React Bricks offers a built-in scheduled publishing feature. This feature can also trigger a build hook in your site's hosting environment when future-dated content is published. ## Schedule Future Publishing With React Bricks, you can keep a page in "draft" status and schedule its future publication. Simply select the desired date and time for publishing. When that moment arrives, your content will automatically transition to the "published" state, making it accessible via the frontend APIs. ## Multischeduling with Variants React Bricks v5 also supports multischeduling through page variants. Instead of scheduling only one future version of a page, you can create multiple variants of the same page and set scheduled publish and unpublish dates for each variant. React Bricks will make the right variant active based on its scheduling window. This is useful for campaign timelines where a page needs to change automatically over time, for example: - a teaser version before launch - a launch-day version - a post-launch version - a seasonal promotion that expires on a specific date When more than one variant is active at the same time, the same variant system can also be used for A/B testing. See [A/B Testing and Multischeduling](/cms-features/ab-testing-multischeduling/) for more details. ## We trigger your build hooks! For static site generation, if you want new content to be published at the scheduled time, you need to call the deploy hook in your hosting environment (e.g., Vercel, Netlify, AWS, GitHub Actions). Don't worry—you won't have to manually trigger the build at midnight to update the website. Just enable the "Trigger hook on scheduled publishing" option for your production build hook. We'll trigger it as soon as the new content is published At midnight, you can simply celebrate with your favorite champagne or, even better, an Italian "metodo classico" 🥂🇮🇹. [Read more about webhooks](/basics/how-to-deploy#build-hooks) and how to set them up. # Security and Governance > Security and governance features for enterprise React Bricks projects. React Bricks includes security and governance features for teams that need stronger control over users, data, and compliance. ## Data residency Enterprise customers can choose EU or US data residency. This is useful when your organization has legal, compliance, or customer requirements about where content data is stored. ## ISO/IEC 27001:2022 React Bricks has obtained ISO/IEC 27001:2022 certification. ISO/IEC 27001 is an international standard for information security management systems. For teams evaluating React Bricks in a security review, this certification can support vendor assessment and governance processes. ## Related features Security and governance also include: - [Single Sign-On](/cms-features/sso/) - [Users, Roles, Permissions](/cms-features/permissions/) - [Approval Workflow](/cms-features/approval-workflow/) - [Multiple Environments](/cms-features/multiple-environments/) - [Backup and Restore](/cms-features/backup-restore/) # SEO > React Bricks offers an advanced SEO module to manage meta tags, open graph, twitter cards and schema.org semantic data. import Video from '@components/Video' React Bricks offers an advanced SEO module. This module allows you to manage meta tags, Open Graph values, and Twitter Cards. When inviting a new user, you can specify whether they have permission to edit SEO attributes for pages. For Enterprise plans, we've also implemented the **full Schema.org model**, complete with all schema entities and semantic data. This feature makes React Bricks an excellent tool for SEO optimization, without requiring a SEO expert in the marketing team. <Video src="/videos/admin_interface/adv_seo.mp4" /> ## Render Metadata and JsonLd data - `renderMeta (page: Page)` renders the Title, all Meta tags, Open graph values, and Twitter Card values. - `renderJsonLd (page: Page)` renders the JsonLd script with all the Schema.org metadata for the page. - `getSchemaOrgData (page: Page)` returns just the stringified Schema.org data without the JsonLd script tag. # Single Sign-On > Configure SAML2 Single Sign-On for the React Bricks visual editing interface with providers such as Microsoft Entra ID, Auth0, Okta, and Google Workspace. import Video from '@components/Video' You can access React Bricks using your preferred SAML2 identity provider, like Microsoft Entra ID, Auth0, Okta, Google Workspace, OneLogin, Ping Identity and others. From the dashboard you can download the metadata to configure the access on your identity provider and then configure your SSO access parameters. {/* photo */} ![SSO Configuration](/images/single-sign-on.webp) ## SSO Login Your developers and content editors will be able to access both the Content administration interface and the Dashboard via SSO, by entering the unique "SSO App Identifier" and then proceeding with the third-party login. If you decide to force the login only via SSO, they won't be able to access using email and password any more. <Video src="/videos/sso_login_opt.mp4" /> # Set Custom Permissions > With React Bricks you can define custom roles and fine-grained permissions for the CMS users. For default roles and permission, refer to [Roles and Permissions](/cms-features/permissions/) ## Custom Roles The Dashboard allows you to create custom Roles, which can be assigned to Users and used to define custom Permissions. ## Custom Permissions Custom permissions are defined using the `permissions` object in the [React Bricks configuration](/common-tasks/customize-react-bricks). Permissions are implemented by providing one of more permission functions. The available permission functions are: - `canAddPage: (user, pageType) => boolean` - `canAddTranslation: (user, pageType, language) => boolean` - `canSeePageType: (user, pageType) => boolean` - `canSeePage: (user, page) => boolean` - `canEditPage: (user, page) => boolean` - `canDeletePage: (user, page) => boolean` - `canDeleteTranslation: (user, page) => boolean` - `canUseBrick: (user, brick) => boolean` The complete description of the `Permissions` type is as follows: ```ts type Permissions = { canAddPage?: (user: PermissionUser, pageType: string) => boolean canAddTranslation?: ( user: PermissionUser, pageType: string, language: string ) => boolean canSeePageType?: (user: PermissionUser, pageType: string) => boolean canSeePage?: ( user: PermissionUser, page: Omit<PermissionPage, 'language'> ) => boolean canEditPage?: (user: PermissionUser, page: PermissionPage) => boolean canDeletePage?: ( user: PermissionUser, page: Omit<PermissionPage, 'language'> ) => boolean canDeleteTranslation?: (user: PermissionUser, page: PermissionPage) => boolean canUseBrick?: (user: PermissionUser, brick: PermissionBrick) => boolean } ``` ## Usage Example Let's say we've created the custom roles `blog_editor` and `translator_fr` in the dashboard. Now, we'll create two permission rules: 1. Prevent all editors from adding `institutional` pages and restrict `blog_editor` users to adding only pages of type `blog`. 2. Prevent `French translators` from deleting translations in languages other than `French`. ```tsx <ReactBricks ... permissions={{ canAddPage: (user, pageType) => { if ( pageType === 'institutional' || user.customRole.id === 'blog_editor' && pageType !== 'blog') { return false } return true }, canDeleteTranslation: (user, page) => { if (user.customRole.id === 'translator_fr' && page.language !== 'fr') { return false } return true } }} > ... </ReactBricks> ``` # Customize React Bricks > Discover how you can customize React Bricks for your specific needs. React Bricks is designed to be highly flexible and customizable to your specific needs. The React Bricks main configuration file is located at `/react-bricks/config.ts`. In this file, you can customize various settings, including the Logo for the Admin header. Many parameters will be pre-configured by the starter, depending on your chosen React framework. ## Configuration object ```ts { appId: string apiKey: string apiPrefix?: string environment?: string bricks?: types.Brick<any>[] | types.Theme[] pageTypes?: types.IPageType[] logo?: string loginUI?: types.LoginUI contentClassName?: string defaultTheme?: string renderLocalLink: types.RenderLocalLink navigate: (path: string) => void loginPath?: string editorPath?: string mediaLibraryPath?: string playgroundPath?: string appSettingsPath?: string previewPath?: string getAdminMenu?: (args: { isAdmin: boolean }) => types.IMenuItem[] isDarkColorMode?: boolean toggleColorMode?: () => void useCssInJs?: boolean appRootElement: string | HTMLElement clickToEditSide?: types.ClickToEditSide customFields?: Array<types.ISideEditPropPage | types.ISideGroup> responsiveBreakpoints?: types.ResponsiveBreakpoint[] enableAutoSave?: boolean disableSaveIfInvalidProps?: boolean enablePreview?: boolean blockIconsPosition?: types.BlockIconsPosition enablePreviewImage?: boolean enablePreviewIcon?: boolean enableUnsplash?: boolean unsplashApiKey?: string enableDefaultEmbedBrick?: boolean checkUnsavedChanges?: boolean permissions?: types.Permissions allowAccentsInSlugs?: boolean warningIfLowBattery?: boolean rtlLanguages?: Array<string> } ``` We can group configuration settings into five main categories: ## 1. Main CMS Configuration | Property | Definition | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `bricks` | Defines content blocks. It's either an array of [Bricks](/bricks/introduction) or a hierarchical structure of [themes](/api-reference/types-reference/types/#theme) » [categories](/api-reference/types-reference/types/#category) » [bricks](/api-reference/types-reference/types/#brick). | | `pageTypes` | Defines page types. It is an array of [Page types](/page-types/) | | `customFields` | Array of custom fields or field groups on a Page, editable via the sidebar's "Page" tab. See [Custom fields](/page-types/custom-fields/) | | `permissions` | Object to specify fine-grained permissions. See [Permissions](/common-tasks/custom-permissions/) | ## 2. Environment settings Except for `logo` and `contentClassName`, all these environment settings are pre-configured by your chosen starter. | Property | Definition | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `appId` | Identifies your React Bricks app. Typically imported from `.env`. It's public, serving as an identifier, not for API authentication. | | `apiKey` | API Key for React Bricks APIs. Typically imported from `.env`. Used to authenticate Read API calls from the frontend. | | `apiPrefix` | Optional API prefix for React Bricks API URLs, such as `xx.api-reactbricks.com`. Used for EU/US data residency and enterprise custom use cases. | | `environment` | Specifies the project environment. See [Multiple environments](/cms-features/multiple-environments/). | | `contentClassName` | Class applied to content in the Admin interface, when a wrapping class name is needed to ensure the editing environment matches the front-end appearance. | | `renderLocalLink` | Functional component wrapping your router Link component (e.g. the Next `<Link>` component). Used by the React Bricks `<Link>`, which renders a `<a>` tag for external URLs and `renderLocalLink` for local paths.<br /><br />Props include:<br />- `href` (required): destination path<br />- `children` (required): link children elements<br />- `className`: class to be applied to links<br />- `activeClassName`: class to be applied to active links<br />- `isAdmin`: true for the admin interface header links.<br /><br />[See `RenderLocalLink`](/api-reference/types-reference/types/#renderlocallink) | | `navigate` | Function to navigate to a page. Typically it uses the framework's navigation function. Required for React Bricks' authentication redirects. | | `loginPath` | Admin "Login" page path. Default: `/admin`. | | `editorPath` | Admin "Editor" page path. Defaults: `/admin/editor`. | | `mediaLibraryPath` | Admin "Media Library" page path. Default: `/admin/media`. | | `playgroundPath` | Admin "Playground" page path. Default: `/admin/playground`. | | `appSettingsPath` | Admin "App Settings" page path. Default: `/admin/app-settings`. | | `previewPath` | Admin "Preview" page path. Default: `/preview`. | | `appRootElement` | String selector (e.g., `#root`) or HTML Element (e.g., `document.getElementById('root')`). Ensures WAI-ARIA compliant accessibility for Admin modals. | | `unsplashApiKey` | Your Unsplash API Key. Required for Unsplash image search functionality. | | `rtlLanguages` | The array of RTL languages: the default is 'ar', 'az', 'dv', 'fa', 'ff', 'he', 'ks', 'ku', 'pa', 'ps', 'ug', 'ur', 'yi' | ### API prefix Use `apiPrefix` when a project needs to target a specific React Bricks API endpoint, for example for EU or US data residency, or for an enterprise-specific API host. Keep the value in environment-specific configuration if different environments use different API hosts. ```ts const config: types.ReactBricksConfig = { appId: process.env.NEXT_PUBLIC_APP_ID!, apiKey: process.env.NEXT_PUBLIC_API_KEY!, apiPrefix: process.env.NEXT_PUBLIC_API_PREFIX, // ... } ``` ## 3. UI configuration | Property | Definition | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `logo` | URL for the logo in the Admin interface header. | | `loginUI` | Object configuring the Login interface UI: sidebar image, logo (with width and height), and welcome message (with CSS styles) [See the LoginUI interface](/api-reference/types-reference/interfaces/#loginui) reference | | `getAdminMenu` | Function receiving the `isAdmin` boolean on the argument object and returning an array of [`IMenuItem`](/api-reference/types-reference/interfaces/#imenuitem).<br /><br />If provided, the `editorPath`, `playgroundPath` and `appSettingsPath` are ignored. | | `clickToEditSide` | Specifies the Viewer's "click-to-edit" button position. Default: `types.ClickToEditSide.BottomRight`. See the [possible values](/api-reference/types-reference/enums/#clicktoeditside). | | `responsiveBreakpoints` | Optional responsive breakpoints for preview. Defaults to `375px`, `768px` and `100%`. Array of objects with the [`BreakPoint` interface](/api-reference/types-reference/interfaces#responsivebreakpoint). | | `blockIconsPosition` | Default: `types.BlockIconsPosition.OutsideBlock`. Set to `types.BlockIconsPosition.InsideBlock` to render block action icons (add before, add after, delete, move up, move down, duplicate) inside the block. | | `defaultTheme` | Default selected theme in the "Add new brick" interface, when you have bricks of multiple themes. | ## 4. Feature flags | Property | Definition | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enableAutoSave` | Default: `true`. Allows users to activate autosave via a switch near the Save button. | | `disableSaveIfInvalidProps` | Default: `false`. If `true`, prevents saving when any sideEditProp is invalid (`validate` function present and not returning `true`) | | `enablePreview` | Default: `true`. Enables the preview button. | | `enablePreviewImage` | Default: `false`. If `true`, enables visual selection of new bricks using images. Requires `previewImageUrl` in the bricks' [schema](/bricks/schema/). | | `enableUnsplash` | Default: `true`. Enables Unsplash image search. | | `enableDefaultEmbedBrick` | Default: `true`. Provides a default "embed" brick type for page embedding. See [Page embed](/bricks/embed). | | `checkUnsavedChanges` | Default: `true`. Warns editors before leaving the editor when there are unsaved changes. | | `allowAccentsInSlugs` | Default: `false`. If `true`, allows accented letters in slugs. | | `warningIfLowBattery` | Default: `false`. If `true`, React Bricks will alert users to save their work or charge their device when battery levels fall below 15% without a power source connected. | ## 5. CSS related | Property | Definition | | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | | `isDarkMode` | A boolean indicating if dark mode is active. Useful to test dark mode while editing, if your Bricks support dark mode. | | `toggleDarkMode` | Function to toggle dark mode. Used to test dark mode in the editor. | | `useCssInJs` | Boolean that must be set to `true` when using a CSS-in-JS library. | # Get data from external APIs > Fetch data from external APIs and render it inside bricks (visually editable content blocks). import Video from '@components/Video' Sometimes you need to fetch data from external sources and render it inside bricks. For instance, when creating a headless commerce system, some product data might come from the headless platform, while other parts of the product details page are visually edited by the marketing team. This approach is also useful when dealing with legacy APIs containing product data sheets. In React Bricks, you can fetch external data at two levels: - **Within each brick** that requires external data - **At the page level**, defined for each pageType Use brick-level fetching when the data belongs to one brick and can be selected or configured from that brick. Use page-level fetching when multiple bricks on the same page need the same external data, such as a product record, event record, or customer profile. ## Fetch external data in a brick This is the most straightforward method, as each brick directly fetches the data it needs. To fetch and use data from external APIs in a brick, define a `getExternalData` function in the brick's schema. This async function returns a promise that resolves to an object, which is then merged with the brick's props. For more details, see the schema's [Connect external APIs](/bricks/schema/connect-external-apis/) documentation. ### Example: fetch product data from a brick prop ```tsx title="ProductPrice.tsx" import { Text, types } from 'react-bricks/rsc' interface ProductPriceProps { sku: string title: types.TextValue price?: string availability?: string } const ProductPrice: types.Brick<ProductPriceProps> = ({ title, price, availability, }) => ( <section> <Text propName="title" value={title} renderBlock={({ children }) => <h2>{children}</h2>} placeholder="Product title..." /> {price && <p>{price}</p>} {availability && <p>{availability}</p>} </section> ) ProductPrice.schema = { name: 'product-price', label: 'Product Price', getDefaultProps: () => ({ sku: 'sku-123', title: 'Product title', }), getExternalData: async (_page, brickProps) => { const response = await fetch( `https://commerce.example.com/products/${brickProps?.sku}` ) const product = await response.json() return { price: product.price.formatted, availability: product.availability, } }, sideEditProps: [ { name: 'sku', label: 'SKU', type: types.SideEditPropType.Text, }, ], } export default ProductPrice ``` ## Fetch external data in pages If multiple bricks need to access the same external data, it may be more efficient to fetch this data at the page level and then allow each brick to use the relevant portion of the data. In this scenario, define `getExternalData` on the `pageType`. For bricks that need to access this data, add a `mapExternalDataToProps` function to their schema. This function maps the external data object on the page to an object that's merged with the brick's props. For more information, refer to the [Page Types](/page-types/) documentation. ### Example: fetch once at page type level ```ts title="react-bricks/pageTypes.ts" import { types } from 'react-bricks/rsc' export const pageTypes: types.IPageType[] = [ { name: 'product', pluralName: 'products', getExternalData: async (page) => { const productId = page.customValues?.productId if (!productId) { return {} } const response = await fetch( `https://commerce.example.com/products/${productId}` ) const product = await response.json() return { product, } }, }, ] ``` Then each brick can pick the part of the page-level data it needs: ```ts title="ProductHero.tsx" ProductHero.schema = { name: 'product-hero', label: 'Product Hero', mapExternalDataToProps: (externalData) => ({ productName: externalData.product?.name, productImage: externalData.product?.image, }), } ``` :::tip[Practical how-tos] For task-oriented examples, see [Fetch external data in bricks](https://www.reactbricks.com/how-tos/integrate-external-data/fetch-external-data-in-bricks), [Fetch external data in page types](https://www.reactbricks.com/how-tos/integrate-external-data/fetch-external-data-in-page-types), and [Generate pages from a visual template and external data](https://www.reactbricks.com/how-tos/integrate-external-data/generate-pages-from-a-template-and-external-data). ::: # Implement A/B Testing > Wire React Bricks A/B Testing variants into routing middleware and analytics. React Bricks A/B Testing is configured in the CMS using page variants and weights. In code, your project needs to resolve the active variant for each request and pass that information to the page rendering and analytics layers. Use this page when you are implementing the developer side of [A/B Testing and Multischeduling](/cms-features/ab-testing-multischeduling/). ## Middleware helpers React Bricks provides two middleware helpers: - [`createAbTestingMiddleware`](/api-reference/utilities/create-ab-testing-middleware/) for Next.js Pages and Astro projects - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) for Next.js App projects where A/B Testing must be chained with the i18n middleware The middleware resolves which variant should be served for the current request. The selected variant is stored in a cookie, so a visitor keeps seeing the same variant across requests. ## Recommended flow 1. Configure variants and weights in React Bricks. 2. Add the appropriate A/B Testing middleware helper to your project. 3. Read the selected variant from cookies in your page route. 4. Pass the variant name to `fetchPage`. 5. Send the test name and variant name to your analytics provider. ## Fetch the stable variant In server-rendered routes, use [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) to read the variant selected by the middleware, then pass it to [`fetchPage`](/api-reference/utilities/fetch-page/) as `variantName`. ```tsx title="app/[lang]/[[...slug]]/page.tsx" import { cookies } from 'next/headers' import { fetchPage, getAbTestingCookie, types } from 'react-bricks/rsc' import config from '@/react-bricks/config' const getData = async ( slug: string | string[] | undefined, locale: string ): Promise<{ page: types.Page | null variantName?: string testName?: string }> => { const cleanSlug = !slug ? '/' : typeof slug === 'string' ? slug : slug.join('/') const cookieStore = await cookies() const variantName = getAbTestingCookie({ slug: cleanSlug, locale, cookieStore, }) const page = await fetchPage({ slug: cleanSlug, language: locale, variantName, config, fetchOptions: { next: { revalidate: 3 } }, }).catch(() => null) return { page, variantName, testName: `${cleanSlug}_${locale}`, } } ``` Then use the same `variantName` when tracking the experiment: ```tsx { testName && variantName && ( <GAExperimentTracker testName={testName} variantName={variantName} /> ) } ``` ## Analytics React Bricks resolves the active variant, but your analytics setup decides how to track impressions and conversions. The usual analytics flow is: - track an impression when a variant is rendered - track conversion events with the same test and variant identifiers - compare conversion rates in your analytics provider The starter projects include middleware and analytics examples on the `ab-testing` branch: [https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps](https://github.com/ReactBricks/reactbricks-starters/tree/feature/ab-testing/apps) ## Related reference - [`createAbTestingMiddleware`](/api-reference/utilities/create-ab-testing-middleware/) - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) - [`getAbTestingCookie`](/api-reference/utilities/get-ab-testing-cookie/) - [`fetchPage`](/api-reference/utilities/fetch-page/) # Implement Email Marketing > Configure email marketing page types and render email HTML from React Bricks content. React Bricks Email Marketing lets editors create email campaigns visually. In code, you model email campaigns as page types and provide the rendering functions needed to generate email HTML. Use this page when you are implementing the developer side of [Email Marketing](/cms-features/email-marketing/). ## Configure an email marketing page type Create a `pageType` with `isEmailMarketing: true`. Email marketing page types can also define: - `renderWrapper`, to wrap the content differently for the Admin preview and the final Email output - `renderEmailHtml`, to generate the final HTML sent to the Email Sending Provider ```tsx title="react-bricks/pageTypes.ts" import { Body, Container, Font, Head, Html, pretty, render, Tailwind, } from '@react-email/components' const pageTypes: types.IPageType[] = [ { name: 'newsletter', pluralName: 'newsletters', isEmailMarketing: true, renderWrapper: (args) => { if (args.renderEnvironment === 'Admin') { return <Container style={{ margin: 'auto' }}>{args.children}</Container> } if (args.renderEnvironment === 'Email') { return ( <Html> <Tailwind> <Head> <Font fontFamily="Nunito Sans" fallbackFontFamily="sans-serif" webFont={{ url: 'https://fonts.gstatic.com/s/nunitosans/v19/pe0AMImSLYBIv1o4X1M8ce2xCx3yop4tQpF_MeTm0lfUVwoNnq4CLz0_kJ3xzHGGVFM.woff2', format: 'woff2', }} fontWeight={400} fontStyle="normal" /> </Head> <Body> <Container style={{ margin: 'auto' }}> {args.children} </Container> </Body> </Tailwind> </Html> ) } return args.children }, renderEmailHtml: async (args) => { const html = await render(args.children) return pretty(html) }, }, ] ``` ## Use email-specific bricks Email clients have stricter rendering rules than browsers. For email content, prefer bricks designed for email output. The starter projects include optional email marketing bricks based on `react-email`, installable from the CLI. ## Editor workflow After the page type is configured, editors can create email marketing pages and select campaign options such as: - Email Sending Provider - list - sender - campaign name - send test, send now, or schedule ## Related reference - [Page Types](/page-types/#properties-definition) - [IPageType type reference](/api-reference/types-reference/interfaces/#ipagetype) - [Email Marketing](/cms-features/email-marketing/) # Implement Localization > Fetch localized React Bricks content and configure i18n routing in your project. React Bricks stores page translations as localized versions of the same page. In code, you usually need to: - request content for the current language - read available translations for language switchers - configure framework routing so localized URLs resolve correctly For the editor workflow, see [Localization](/cms-features/localization/). ## Fetch localized content Queries for page lists or single page content accept a `language` parameter, allowing you to request content in a specific language. When retrieving content without specifying a language, React Bricks returns the default language. ### usePagesPublic The `usePagesPublic` hook has a `language` argument to return the published pages in the desired language. See [`usePagesPublic`](/api-reference/hooks/use-pages-public/). ### fetchPages The `fetchPages` helper function can specify a `language` in the `options` object. See [`fetchPages`](/api-reference/utilities/fetch-pages/). ### usePagePublic The `usePagePublic` hook has `slug` and `language` arguments, so you can request a specific translation when more than one page has the same slug. See [`usePagePublic`](/api-reference/hooks/use-page-public/). ### fetchPage The `fetchPage` helper function has `slug`, `apiKey` and `language` arguments, so you can request the translation you want. See [`fetchPage`](/api-reference/utilities/fetch-page/). ## Page translations A `Page` object from the query hooks (`usePagesPublic`, `usePagePublic`) or fetch helper functions (`fetchPages`, `fetchPage`) has a `translations` field containing the available translations for that page. Each translation includes the language, slug, page name, status, edit status, lock state and scheduled publishing date. ```ts type Page = { // ... translations: Translation[] } type Translation = { language: string slug: string name: string status: PageStatus editStatus: EditStatus isLocked: boolean scheduledForPublishingOn: string } ``` Use `translations` to build language switchers and link users to the matching localized URL. ## Next.js Pages routing Next.js Pages projects can use Next.js built-in internationalization routing. React Bricks starters with Next.js Pages are pre-configured to use i18n routing. Add languages to the `locales` array in `next.config.js`: ```js {3} module.exports = { i18n: { locales: ['en', 'it'], defaultLocale: 'en', localeDetection: false, }, } ``` To fetch localized content in Next.js Pages, use the `locale` from `context`: ```ts export const getStaticProps: GetStaticProps = async (context) => { const { slug } = context.params try { const page = await fetchPage(slug.toString(), config.apiKey, context.locale) return { props: { page } } } catch { return { props: { error: 'NOPAGE' } } } } ``` ## Next.js App and Astro middleware [`createI18nMiddleware`](/api-reference/utilities/create-i18n-middleware/) makes i18n routing easier to manage in Next.js App and Astro projects. Use it when your project has localized routes and you want middleware to resolve the correct language before rendering. If the same Next.js App project also uses A/B Testing, use [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) to chain A/B Testing with i18n middleware. ## Related docs - [Localization CMS feature](/cms-features/localization/) - [`createI18nMiddleware`](/api-reference/utilities/create-i18n-middleware/) - [`createWithAbTestingMiddleware`](/api-reference/utilities/create-with-ab-testing-middleware/) # Reuse Content Across Pages > Discover how to reuse content across pages in React Bricks. React Bricks offers several methods for reusing content across pages. In this section, we'll summarize these methods, highlighting the use case for each and providing links to the relevant documentation. ## Summary | Reusing content need | How to achieve it | | ---------------------------------------------- | ---------------------------------- | | "Cookie cutter" to reuse bricks' configuration | Stories | | "Change once, apply everywhere" block | Embed | | Layout fragment, like header and footer | Dedicated `<PageViewer>` in layout | ## Stories Stories are a way to save and reuse a brick's configuration, reapplying the same set of props. They can be created in code, pre-configuring a single brick into different relevant configurations, or by content editors to save and reuse a particular brick configuration. Bricks configured using a story aren't bound to that story: changing the story afterwards won't affect the bricks created using that story, much like changing a cookie cutter shape won't affect cookies already baked. Read the [Stories](/bricks/schema/stories/) documentation. ## Embed Embed bricks allow you to embed the content of a page inside other pages. In this case, changing the original page will affect all the pages embedding it, updating them accordingly. This provides a single source of truth, useful for elements like CTAs that you want to change everywhere on your website simultaneously. Read the [Embed](/bricks/embed) documentation. ## Header and Footer Some layout elements, like header and footer, are shared across all pages of a website. It's usually better not to use an embed for these elements to avoid triggering a fetch of these header and footer entities for every page during the build process. Instead, it's more efficient to have two dedicated `<PageViewer>`s in the layout rendering the children routes, as seen in the starter projects scaffolded by the CLI. You can create the header and footer pages under a dedicated `pageType` with `isEntity` set to true. This makes them visible under the "Entities" tab rather than among all other pages. # Submit Forms > Use form bricks and sendFormSubmission to send form data to React Bricks. React Bricks Form Management lets teams configure form actions from the dashboard. In code, you create form bricks that collect values from visitors and submit them to React Bricks. Use this page when you are implementing the developer side of [Form Management](/cms-features/form-management/). ## Create the form in the dashboard First, create a form from the React Bricks dashboard. There you can configure what happens when the form is submitted: - save submitted data - send an email with the submitted data - subscribe the visitor to an Email Sending Provider list - call a Zapier webhook ## Build a form brick A form brick is a normal React Bricks brick that renders form fields and handles submission. In practice, it should: 1. Render the form fields. 2. Collect the submitted values. 3. Call [`sendFormSubmission`](/api-reference/utilities/send-form-submission/) with the app data, token, form identifier, submitter email address, submitted data, and fetch options. 4. Show a success or error state to the visitor. ## Submit the data Inside the submit handler, call `sendFormSubmission` and use the returned `success`, `statusCode`, and `message` values to update the form UI. ```ts try { const result = await sendFormSubmission({ appId: rbContext.appId, appEnv: rbContext.environment, token, formId, emailAddress: email, data, fetchOptions: { apiPrefix: rbContext.apiPrefix }, }) if (result.success) { // Show a success state. } else { // Show result.message or a fallback error. } } catch (err) { // Handle network or unexpected errors. } ``` See the [`sendFormSubmission` reference](/api-reference/utilities/send-form-submission/) for the full TypeScript signature. ## Spam protection React Bricks forms support Google reCAPTCHA v3 protection. Use reCAPTCHA for public forms where you need protection against automated submissions. ## Related reference - [`sendFormSubmission`](/api-reference/utilities/send-form-submission/) - [Form Management](/cms-features/form-management/) # Get images from Unsplash > Configure Unsplash image search in the React Bricks Media Library. import Video from '@components/Video' In the Media Library (DAM), editors can search for images from Unsplash by entering keywords and selecting the desired aspect ratio (vertical, horizontal, or square) and primary color. <Video src="/videos/admin_interface/media_load_unsplash_opt.mp4" /> ## Provide your Unsplash API Key To use this feature, you need to set your `unsplashApiKey` in the [React Bricks Configuration](/common-tasks/customize-react-bricks/). Without this API key, React Bricks will use our proxy APIs to Unsplash with a limited rate of 20 searches per hour per app, allowing you to test the feature. :::note This feature is enabled by default. You can disable it by setting `enableUnsplash` to false in the [React Bricks Configuration](/common-tasks/customize-react-bricks/). ::: # What is React Bricks? > What is React Bricks, architecture of a React-based headless CMS with visual editing, universal CMS. import { Steps } from '@astrojs/starlight/components' import Rive from '@components/Rive.astro' ## Headless, yet Visual **React Bricks is a headless CMS with visual editing capabilities, based on React components, for Next.js and Astro.** This type of CMS is now also known as [Universal CMS](https://dev.to/matfrana/what-is-a-universal-cms-28n4). It sacrifices a bit of the "purity" of traditional headless CMSs to provide a superior experience for content editors, bridging the gap created by headless CMS adoption, which left content editors behind. It also enhances the developer experience (DX) by leveraging pure React and TypeScript development. ![React Bricks Universal CMS](../../../../public/images/universal-cms-vs-headless-vs-visual-builders.png) ## Architecture React Bricks comprises two key elements: 1. **A React library** for creating visually editable content blocks ("bricks") using React and TypeScript 2. **A SaaS backend** where content is stored ![React Bricks Architecture](../../../../public/images/universal-cms-architecture.png) **Developers create custom "content bricks" in their repository** using components from the React Bricks library to enable visual editing (e.g. Text, Image, Repeater). Each brick has a unique name within the design system. **The backend APIs are unaware of how content bricks are created in code or their appearance**. They simply store a JSON representation of the content for each page or entity. You can visualize the content for each page as an array of blocks, each containing the name of the corresponding brick in code and all the properties edited by content editors. **The library matches the database content with the bricks in code, rendering the correct brick** and passing it the necessary properties to display the content. This happens both in the Admin (content management interface) and in the Page Viewer (used in frontend pages). ## Content Management interface ![React Bricks Content Management Interface](../../../../public/images/universal-cms-content-management.png) The content management interface is integrated within the frontend project, sharing the repository with bricks and frontend pages. This allows customers to host both the website and content management interface on their preferred platform. This approach differs from the typical headless CMSs, which usually provide a hosted content management interface. ## Enterprise-ready React Bricks is **feature-rich**, offering comprehensive Digital Asset Management (DAM), advanced SEO, localization, scheduled publishing, real-time collaboration, content versioning, external data integration and image optimization. Furthermore, it's **enterprise-ready** with Single Sign-On (SSO), granular permissions, approval workflows, off-site backups and dedicated enterprise support. ## Adoption Process **Using the CLI, you can quickly set up a Next.js or Astro project** with both frontend and content management interfaces. This project can be hosted on any platform supporting your chosen framework, such as Vercel, Netlify, AWS, or Azure. You can leverage existing React components and your team's React skills to create visual content blocks quickly, using the React Bricks library. <Rive src="/videos/reactbricks_update.riv" id="reactbricks_update" stateMachines="reactbricks_update" /> {/* prettier-ignore */} <Steps> 1. Developers create bricks using TypeScript and React within their code repository. Each brick has a `schema` defining its properties, including a unique brick name. 2. Content editors use these bricks to compose pages with inline visual editing directly on the formatted content. This eliminates the need for an "instant preview" feature, as editors work directly on the styled content. The content is stored in structured JSON format on the React Bricks APIs. Each block on a page references a specific brick name and contains its associated props. 3. The React Bricks library renders the website content by matching the database-stored content with the corresponding bricks in code. </Steps> # Why React Bricks? > Why React Bricks visual editing vs a pure headless CMS. import Video from '@components/Video' Traditional headless CMSs face two main challenges: 1. **Poor user experience**. Content editors dislike filling out dull forms. They prefer a word processor-like experience, where they can edit content directly and see instant results. 2. **Dependency on developers**. Content and marketing teams lack autonomy, constantly requiring developer assistance. Visual tools like Wix or Webflow address these issues but introduce a new problem: they give editors too much design freedom. This can lead to brand inconsistency and design system violations. ## Bricks of content Remember your childhood Lego adventures? With those simple, standardized bricks you could build anything. Each piece remained unchanged, yet the possibilities were endless. **We introduce "Bricks"** — visually editable blocks that the content and marketing teams use to compose pages. Each brick has built-in constraints to maintain design system integrity. Developers can craft their own "Lego set" of bricks using React code, empowering content editors to work independently. **Bricks enable "Controlled Freedom" for content editors**, allowing developers to delegate the right level of freedom for each content block. They provide a great React-based developer experience (DX) and unmatched ease of use for content editors through true visual editing. <Video src="/videos/adv-features/visual_editing.mp4" /> ## What's in it for you? React Bricks offers several advantages that bring measurable impact to your content management solution: - **Save developers' time** by empowering content editors to work autonomously - **Boost content editors' efficiency** with an intuitive, visual interface - **Seamlessly implement your design system** while preserving brand identity - **Achieve top-tier website performance** using a modern React framework, optimized images, and global CDN - **Enjoy the freedom** to choose your preferred hosting provider, React framework and CSS library - **Leverage enterprise-grade features** tailored for structured organizations # Getting Started > Getting started with React Bricks CLI is very easy. Set up a Next.js or Astro project in minutes. import Video from '@components/Video' import { Tabs, TabItem, Steps } from '@astrojs/starlight/components' In this section we'll see how to create a new React Bricks project from scratch in just a few minutes, following two simple steps: {/* prettier-ignore */} <Steps> 1. [Sign up](https://www.reactbricks.com/sign-up) for a free account 2. Start a new project using the [`create reactbricks-app` CLI command](#react-bricks-cli) </Steps> ## Prerequisites - **Node.js** - `v18` or higher. - **Text editor** - We recommend [VS Code](https://code.visualstudio.com/) with our [React Bricks snippets extension](https://marketplace.visualstudio.com/items?itemName=ReactBricks.react-bricks-snippets). - **Terminal** - To be able to launch the React Bricks command-line interface (CLI) and start the Next.js or Astro project. ## React Bricks CLI Run the following command in your terminal to start our install wizard: {/* prettier-ignore */} <Tabs> <TabItem label="npm"> ```shell # create a new project with npm npm create reactbricks-app@latest ``` </TabItem> <TabItem label="pnpm"> ```shell # create a new project with pnpm pnpm create reactbricks-app@latest ``` </TabItem> <TabItem label="yarn"> ```shell # create a new project with yarn yarn create reactbricks-app ``` </TabItem> </Tabs> You can run `create reactbricks-app` in your root development directory. There's no need to create a new empty directory for your project beforehand, as the wizard will create one for you automatically. Then: 1. **Answer the questions and follow the instructions of the CLI wizard.** You'll be able to authenticate, choose an existing app or create a new one, choose a project name and template, and pick your preferred framework, such as Next.js with App or Pages Router, or Astro. 2. If successful, you will see a success message followed by recommended next steps. Once your project is created, you can `cd` into your new project directory and start your app. The command to start it depends on your chosen framework (for example, if you chose Next.js, it is `npm run dev`). Here you can see a video of the CLI in action: <Video src="/videos/RB_CLI_opt.mp4" /> ## Try editing content Once your project has started, open it in your browser (usually at `http://localhost:3000`) and click the "Edit content" button (or go to the `/admin` folder). You'll enter the content administration area of React Bricks, where you can log in (using the credentials you chose during registration) and try visually editing some pages. ## Edit your project **To make changes to your project, open your project folder in your code editor.** Working in development mode with the dev server running allows you to see updates to your site as you edit the code. **As a first step, explore the directory structure.** You'll find the `admin` folder containing the content management interface and the `react-bricks` folder with the configurations. Inside `react-bricks`, there is a `bricks` folder where you'll find some pre-made content blocks and where you'll be able to create your own bricks to match your corporate design system. ## Next steps Congratulations! You've just created your first React Bricks project! 🎉 You are now ready to start building something beautiful! Before diving in, we recommend learning the basics of React Bricks through one of our many learning resources like the [interactive tutorial](https://www.reactbricks.com/interactive-tutorial), a [1-hour video workshop](https://www.youtube.com/watch?v=Nf7XCKwi2tY), or [how-tos](https://www.reactbricks.com/how-tos). # How to Learn > Discover all the resources to learn how to develop with React Bricks visual CMS for React. import { CardGrid, LinkCard, Steps } from '@astrojs/starlight/components' We are committed to making the React Bricks adoption experience as streamlined as possible. With our [Interactive Tutorial](https://reactbricks.com/interactive-tutorial) and [Video workshop](https://www.youtube.com/watch?v=zAKolGc4dLM), you can be up and running with React Bricks in just 2 to 3 hours. ## Learning Resources The best resources to learn React Bricks are: <CardGrid> <LinkCard title="Interactive Tutorial" description="Learn at your own pace with this gamified tutorial." href="https://www.reactbricks.com/interactive-tutorial" /> <LinkCard title="Video workshop" description="A 1-hour session with our CTO, Matteo Frana." href="https://www.youtube.com/watch?v=Nf7XCKwi2tY" /> <LinkCard title="This documentation" description="Ready for a deep dive? You're in the right place." href="https://docs.reactbricks.com" /> <LinkCard title="How-tos" description="Task-oriented guides for common React Bricks workflows." href="https://www.reactbricks.com/how-tos" /> </CardGrid> # Page Types > React Bricks Page types are a way to group similar pages and apply specific configurations to them. Page types are a way to group similar pages and apply specific configurations to them. A Page Type can define: - **A Template**. See [Page Templates](/page-types/page-templates) - **Allowed / excluded block types** - **Default status for new pages**: locked or unlocked, draft or published - **Default content, language** and **featured image** - **Featured image aspect ratio** - **Custom fields**, if any - **The `getExternalData` function** to get data from external APIs - **Categories** to organize the pages - **A Slug Prefix** enforced by the editor - **Headless View** when you just need to edit custom fields with no visual editing In [React Bricks configuration](/common-tasks/customize-react-bricks/), `pageTypes` is an array of `pageType` objects. For starter projects, you'll find a `pageTypes.ts` file in the `/react-bricks` directory. ## Usage Example ```tsx const pageTypes: types.IPageType[] = [ ...{ name: 'post', pluralName: 'posts', defaultLocked: false, defaultStatus: types.PageStatus.Draft, getDefaultContent: () => ['title'], allowedBlockTypes: ['title', 'paragraph', 'image', 'video', 'code'], }, ] ``` ## Properties Each pageType object has the following shape: ```ts interface IPageType { name: string pluralName: string isEntity?: boolean isEmailMarketing?: boolean headlessView?: boolean allowedBlockTypes?: string[] excludedBlockTypes?: string[] defaultLocked?: boolean defaultStatus?: PageStatus defaultFeaturedImage?: string getDefaultContent?: () => (string | IBrickStory | IContentBlock)[] customFields?: Array<ISideEditPropPage | ISideGroup> getExternalData?: (page: Page) => Promise<Props> getDefaultMeta?: (page: PageFromList, externalData: Props) => Partial<IMeta> metaImageAspectRatio?: number categories?: ICategory[] slugPrefix?: { default: string translations?: { [key: string]: string } } template?: Array<TemplateSlot> renderWrapper?: (args: IRenderWrapperArgs) => React.ReactElement renderEmailHtml?: (args: { children: React.ReactElement page: PageValues }) => Promise<string> | string } ``` ## Properties definition | Property | Definition | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | The unique name for this page type (e.g., "product"). | | `pluralName` | The plural name used in the editing interface (e.g., "Products"). | | `isEntity` | Boolean (default false). If true, pages of this type will be organized under the "Entities" tab in the left sidebar. This provides a useful logical separation for editors to understand which pages are meant as reusable fragments or entities and are not true pages. | | `isEmailMarketing` | Boolean (default false). If true, pages of this type are treated as email marketing pages. See [Implement Email Marketing](/common-tasks/implement-email-marketing/). | | `headlessView` | Boolean (default false). If true, pages of this type will show a "form" interface to edit custom fields, with no visual editing of content. | | `allowedBlockTypes` | Array of block type names allowed for this page type. By default, all block types are allowed. | | `excludedBlockTypes` | Array of block type names not allowed for this page type. Useful when most block types are allowed. React Bricks will exclude blocks found in this list or not found in `allowedBlockTypes` if provided. | | `defaultLocked` | The default lock status for new pages. Set to true for pages with a fixed structure. | | `defaultStatus` | The default visibility status (draft or published) for new pages of this type. | | `defaultFeaturedImage` | The default URL for the featured image of this pageType, used if no featured image is provided via the Document sidebar. | | `getDefaultContent` | Function that returns the default content for a new page of this type. It can return strings (brick names), [IBrickStory](/api-reference/types-reference/interfaces/#ibrickstory) objects, or [IContentBlock](/api-reference/types-reference/interfaces/#icontentblock) objects. | | `customFields` | Array of custom fields or groups of custom fields for this page type, editable via the sidebar's "Document" tab. See [Custom fields](/page-types/custom-fields) | | `getExternalData` | Function that takes a [Page](/api-reference/types-reference/types#page) as argument and returns a promise resolving to an object with string keys. See [External content](/common-tasks/get-data-from-external-apis) | | `getDefaultMeta` | Function that takes a [Page](/api-reference/types-reference/types#page) and [External Data](/common-tasks/get-data-from-external-apis) as arguments and returns a object with type [IMeta](/api-reference/types-reference/interfaces/#imeta) (or partial) with meta data, Open Graph data, X (Twitter) card data, Schema.org data. Useful for populating meta from an external API, like a headless commerce system. | | `metaImageAspectRatio` | Aspect ratio for cropping the featured image in the page meta. | | `categories` | Array of objects with interface [`ICategory`](/api-reference/types-reference/interfaces/#icategory) to organize pages within this pageType. Editors can select a category from this list, and pages will be organized accordingly in the left sidebar menu. | | `slugPrefix` | Prefix to apply to the slug of each page in this pageType, with its default value and values for each locale. | | `template` | A Page Template, defined as a set of Slots. See [Page Template](/page-types/page-templates/). | | `renderWrapper` | Function to render a wrapper around the page content. The arguments are the children to wrap, the page and the render environment (admin, frontend, preview or email). | | `renderEmailHtml` | Function to generate the final HTML for email marketing pages. It can use tools such as the `render` function from `react-email`. See [Implement Email Marketing](/common-tasks/implement-email-marketing/). | ## Email marketing page types Set `isEmailMarketing: true` when a page type represents email campaigns instead of website pages. Email marketing page types can define: - `renderWrapper`, to wrap the content before React Bricks renders it - `renderEmailHtml`, to generate the final HTML sent to the Email Sending Provider `renderWrapper` can return different wrappers for the Admin and Email render environments. For example, you can keep the Admin preview constrained with a `Container`, while wrapping the Email output with the required `Html`, `Head`, `Body` and `Tailwind` components. `renderEmailHtml` receives the rendered React children and the page values. For email templates based on `react-email`, you can return the result of its `render` function, optionally formatted with `pretty`. ```tsx title="react-bricks/pageTypes.ts" import { Body, Container, Font, Head, Html, pretty, render, Tailwind, } from '@react-email/components' const pageTypes: types.IPageType[] = [ { name: 'newsletter', pluralName: 'newsletters', isEmailMarketing: true, renderWrapper: (args) => { if (args.renderEnvironment === 'Admin') { return <Container style={{ margin: 'auto' }}>{args.children}</Container> } if (args.renderEnvironment === 'Email') { return ( <Html> <Tailwind> <Head> <Font fontFamily="Nunito Sans" fallbackFontFamily="sans-serif" webFont={{ url: 'https://fonts.gstatic.com/s/nunitosans/v19/pe0AMImSLYBIv1o4X1M8ce2xCx3yop4tQpF_MeTm0lfUVwoNnq4CLz0_kJ3xzHGGVFM.woff2', format: 'woff2', }} fontWeight={400} fontStyle="normal" /> </Head> <Body> <Container style={{ margin: 'auto' }}> {args.children} </Container> </Body> </Tailwind> </Html> ) } return args.children }, renderEmailHtml: async (args) => { const html = await render(args.children) return pretty(html) }, }, ] ``` Pages created from an email marketing page type show campaign settings in the editor, such as the Email Sending Provider, list, sender, campaign name, and send or schedule actions. See also [Email Marketing](/cms-features/email-marketing/) and [Implement Email Marketing](/common-tasks/implement-email-marketing/). :::tip[Practical how-tos] For task-oriented examples, see [Create a page type](https://www.reactbricks.com/how-tos/page-types/create-a-page-type), [Use page metadata](https://www.reactbricks.com/how-tos/page-types/use-page-meta-data), and [List pages by type](https://www.reactbricks.com/how-tos/page-types/list-pages-by-type). ::: ## Usage Example with Template ```tsx const pageTypes: types.IPageType[] = [ ...{ name: 'product', pluralName: 'products', defaultStatus: types.PageStatus.Published, template: [ { slotName: 'heading', label: 'Heading', min: 1, max: 1, allowedBlockTypes: ['hero-unit'], editable: true, getDefaultContent: () => [ // Default content defined with a story { brickName: 'hero-unit', storyName: 'gradient-hero-unit' }, ], }, { slotName: 'content', label: 'Content', min: 0, max: 4, allowedBlockTypes: [ 'text-image', 'call-to-action', 'customers', 'paragraph', ], editable: true, getDefaultContent: () => ['text-image', 'customers'], }, { slotName: 'footer', label: 'Footer', min: 1, max: 1, allowedBlockTypes: ['call-to-action'], editable: false, // no default content => you'll get 1 block // of type call-to-action because of min: 1 }, ], }, ] ``` ## Render a list of pages with `<List>` Using the `<List>` components, it's possible to easily render a list of pages of a certain pageType without calling the `fetchPages` function (or using the `usePages` hook). ### Properties Here's the List component interface: ```ts interface ListProps { of: string where?: { tag?: string language?: string filterBy?: { [key: string]: any } } sort?: string page?: number pageSize?: number children: ({ items, pagination, }: types.PagesFromListWithPagination) => React__default.ReactElement } ``` ### Properties definition | Property | Definition | | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `of` | The page type of the pages to fetch. | | `where` | Filter by tag, language or custom fields | | `sort` | Sort (minus sign before the field name to sort descending) | | `page` | The page number (for pagination) | | `pageSize` | The page size (for pagination) | | `children` | The children should be a function with an object as argument, from which you can get `items` and `pagination` to render each item of the list. | ### Usage example ```tsx <List of="blogPost" where={{ language: 'fr', tag: 'cms', filterBy: { myCustomField: 'foo' }, }} sort="-publishedAt" page={1} pageSize={20} > {({ items, pagination }) => { return ( <> {items.map((post) => { return ( <PostListItem key={post.id} title={post.meta.title || ''} href={post.slug} content={post.meta.description || ''} author={post.author} date={post.publishedAt || ''} featuredImg={post.meta.image} /> ) })} </> ) }} </List> ``` # Custom Fields > In React Bricks you can configure custom fields for each page type. For each pageType, you can configure an array of custom fields with their respective types. These custom fields are editable via sidebar controls for each page of that type, allowing you to have structured data on the page alongside the block content. Custom fields are defined in the `customFields` property of a page type. The structure of this array is identical to the [`sideEditProps`](/bricks/schema/side-edit-props/) of a brick, enabling you to use all sidebar control types and organize custom fields into collapsible sections. For more information, please refer to the [brick's sidebar controls](/bricks/schema/side-edit-props/) documentation. ## Usage Example ```ts pageTypes: [ ...{ name: 'product', pluralName: 'products', customFields: [ { name: 'productID', label: 'Product ID', type: types.SideEditPropType.Text, }, ], }, ] ``` ## Custom Fields for all Page Types If you have custom fields that apply to all page types, you can define them in the `customFields` property of the root [React Bricks configuration](/common-tasks/customize-react-bricks/). # Page Templates > Page templates let you configure a set of predefined slots for a page type. ## Introduction Page templates let you configure a set of predefined slots for a [pageType](/basics/pages-and-page-types). Each slot is a fixed part of the page with a `name`, `label`, `min` and `max` number of blocks and `allowedBricks`. It can be `editable` or not and have default content, defined by the `getDefaultContent` function. Templates are ideal for pages like e-commerce product details, where you have fixed sections that may fetch data from external APIs, as well as more flexible areas for content editors to customize. :::tip[Practical how-to] For a step-by-step guide, see [Create a page template](https://www.reactbricks.com/how-tos/page-types/create-a-page-template). ::: ## Properties Each template object has the following shape: ```ts type TemplateSlot = { slotName: string label: string min?: number max?: number allowedBlockTypes?: string[] excludedBlockTypes?: string[] editable?: boolean getDefaultContent?: () => (string | IBrickStory | IContentBlock)[] } ``` ## Properties definition | Property | Definition | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `slotName` | The name for the slot, unique for the pageType. | | `label` | Label for the slot showed in the editing interface. | | `min` | Minimum number of bricks | | `max` | Maximum number of bricks | | `allowedBlockTypes` | The bricks allowed in this slot | | `excludedBlockTypes` | The bricks not allowed in this slot | | `getDefaultContent` | Function that returns the default content for a new page of this slot.<br />If the function returns a string for a block, it should be a brick name: the default content for that brick will be used to populate the block.<br />In case of an [IBrickStory](/api-reference/types-reference/interfaces/#ibrickstory), a particular story of the brick is used to populate the block.<br />In case of IContentBlock you can provide the exact content block (id, type and props). | ## Usage example ```tsx const pageTypes: types.IPageType[] = [ { name: 'product', pluralName: 'products', defaultStatus: types.PageStatus.Published, template: [ { slotName: 'heading', label: 'Heading', min: 1, max: 1, allowedBlockTypes: ['product-heading'], editable: true, }, { slotName: 'content', label: 'Content', min: 0, max: 4, allowedBlockTypes: [ 'text-image', 'product-info', 'carousel', 'paragraph', ], editable: true, getDefaultContent: () => ['product-info', 'carousel'], }, { slotName: 'related-products', label: 'Related Products', min: 1, max: 1, allowedBlockTypes: ['related-products'], editable: false, }, ], }, // ... ] ``` ## Rendering single Slots Once you define slots on a page template, you can also render single slots instead of a full page. Rather than using `<PageViewer page={page}>`, you can render a single slot using the `<Slot>` component: ```tsx <Slot page={page} name="heading"> ``` # What changes for RSC > Discover how React Bricks works with React Server Components (RSC) in Next.js projects using the App Router. Starting from v4.2 React Bricks supports React Server Components (RSC) with the `react-bricks/rsc` package. If you would like to know more about RSC, we suggest to read the [Where do React Server Components fit in the history of web development](https://dev.to/matfrana/where-do-react-server-components-fit-in-the-history-of-web-development-1l0f) article by Matteo Frana and also [Making Sense of React Server Components](https://www.joshwcomeau.com/react/server-components/) by Josh Comeau. As Next.js is the first framework leveraging React Server Components, RSC are now available in the Next.js starters with the App Router. If you scaffold a new project from the CLI using the "Next.js with App Router" starter, you will have a complete project using React Bricks in the React Server Components flavour. Server components are a completely new paradigm and this imposed some changes to the React Bricks APIs in the `react-bricks/rsc` package. In this section of the documentation, you will find everything that changes when using Server Components with an RSC-enabled starter and the `react-bricks/rsc` package. ## New packages: `/rsc` and `/rsc/client` ### Server components In Server Components, the following items should be imported from `react-bricks/rsc`: `File`, `Image`, `JsonLd`, `Link`, `PageViewer`, `Plain`, `Repeater`, `RichText`, `RichTextExt`, `Text`, `blockPluginConstructor`, `blockWithModalPluginConstructor`, `cleanPage`, `fetchPage`, `fetchPages`, `fetchTags`, `getPagePlainText`, `markPluginConstructor`, `plugins`, `types` While the following imports are not available for Server Components: `Preview`, `Meta`, `getSchemaOrgData`, `renderJsonLd`, `renderMeta`, `useAdminContext`, `usePage`, `usePagePublic`, `usePageValues`, `usePages`, `usePagesPublic`, `useReactBricksContext`, `useTagsPublic`, `useVisualEdit`, ### Client components In Client Components (with 'use client'), the following items should be imported from `react-bricks/rsc/client`: `ReactBricks`, `useAdminContext`, `usePageValues`, `useReactBricksContext`, `useVisualEdit`, `types` ## Hooks replacements for server components ### isAdmin ```ts isAdmin(): boolean ``` Function which returns `true` if execution runs inside the Admin interface, `false` otherwise. It replaces the `useAdminContext` hook, not available for server components. ### getPageValues ```ts getPageValues(): types.PageValues | null ``` Function which returns the [pageValues](/api-reference/types-reference/types/#pagevalues) of the current page. It replaces the `usePageValues` hook, not available for server components. ## For client components ### register ```ts register(config: types.ReactBricksConfig): void ``` Function that initializes the React Bricks configuration so that it is available to render the page with RSC. This function should be invoked before using any component or function imported from `react-bricks/rsc`. ### wrapClientComponent ```ts wrapClientComponent<T>({ ClientComponent: React.FC<T>, RegisterComponent: React.FC<any>, schema: types.IBlockType<T>, }): types.Brick<T> ``` Function which wraps a client component (a component with `'use client'`) and, adding the `schema`, returns a React Bricks' brick. RegisterComponent is a function from `react-bricks/rsc/client`. ## Meta data ### getMetadata ```ts getMetadata(page: types.Page): IMetadata ``` Next.js 14+ with the App Router has its way of managing meta data. This function returns the page metadata so that they are compatible with Next.js Metadata. ## Preview link ### fetchPagePreview ```ts fetchPagePreview({   token: string   config: types.ReactBricksConfig   fetchOptions?: types.FetchOptions }): Promise<types.Page> ``` Function which fetches the page data so that it can be viewed in a preview link. It is an alternative solution to the [`<Preview>` component](/api-reference/components/preview/) used in the non-RSC library. ## Other functions ### getBlockValue ```ts getBlockValue(propName: string): any | null ``` Function which returns the value of the propName for the current block in a server component. ### getBricks ```ts getBricks(): types.Bricks ``` Function to get all the configuration's bricks in a server component. ## Under `react-bricks/rsc/client` ### RegisterComponent ```ts RegisterComponent: React.FC<RegisterComponentProps> type RegisterComponentProps = { page: types.Page; block: types.IContentBlock } ``` Function to be used together with `wrapClientComponent` to create bricks from client components. ### ClickToEdit ```ts ClickToEdit: React.FC<ClickToEditProps> interface ClickToEditProps { pageId: string language?: string editorPath: string clickToEditSide?: types.ClickToEditSide } ``` Client component that shows the icon to edit the page when a user is viewing the frontend website while logged in the admin interface. ## Updated Components When using React Server Components, the visual components (Text, RichText, Image, File Repeater, Link) must be imported from `react-bricks/rsc` and they have a slightly different APIs, as we need to pass them the value of the prop. ## Text Add the `value` prop. You get it from the component's props. The type should be declared as `ReactBricks.types.TextValue`. #### Before ```tsx import { Text } from 'react-bricks/frontend' ... <Text propName="title" placeholder="Enter the title" renderBlock={({ children}) => ( <p className="text-xl"> {children} </p> )} > ``` #### After ```tsx // highlight-next-line import { Text } from 'react-bricks/rsc' ... <Text propName="title" // highlight-next-line value={title} placeholder="Enter the title" renderBlock={({ children}) => ( <p className="text-xl"> {children} </p> )} > ``` ## RichText Add the `value` prop. You get it from the component's props. The type should be declared as `ReactBricks.types.TextValue`. #### Before ```tsx import { RichText } from 'react-bricks/frontend' ... <RichText propName="title" placeholder="Enter the title" renderBlock={({ children}) => ( <h1 className="text-xl"> {children} </h1> )} > ``` #### After ```tsx // highlight-next-line import { RichText } from 'react-bricks/rsc' ... <RichText propName="description" // highlight-next-line value={description} placeholder="Enter the description" renderBlock={({ children}) => ( <p> {children} </p> )} allowedFeatures={[types.RichTextFeatures.Bold]}, > ``` ## Image Add the `source` prop. You get it from the component's props. The type should be declared as `ReactBricks.types.IImageSource`. #### Before ```tsx import { Image } from 'react-bricks/frontend' ... <Image propName="avatar" alt="Avatar" /> ``` #### After ```tsx // highlight-next-line import { Image } from 'react-bricks/rsc' ... <Image propName="avatar" // highlight-next-line source={avatar} alt="Avatar" /> ``` ## File Add the `source` prop. You get it from the component's props. The type should be declared as `ReactBricks.types.IFileSource`. #### Before ```tsx import { File } from 'react-bricks/frontend' ... <File propName="document" /> ``` #### After ```tsx // highlight-next-line import { File } from 'react-bricks/rsc' ... <File propName="document" // highlight-next-line source={document} /> ``` ## Repeater Add the `items` prop. You get it from the component's props. The type should be declared as `ReactBricks.types.RepeaterItems<T>` where T (not mandatory) is the type of the single repeated item (you can import it from the repeated brick). If you specify T, you have the result of `getDefaultProps` fully typed also for repeated items. #### Before ```tsx import { Repeater } from 'react-bricks/frontend' ... <Repeater propName="features" /> ``` #### After ```tsx // highlight-next-line import { Repeater } from 'react-bricks/rsc' ... <Repeater propName="features" // highlight-next-line items={features} /> ``` # Client (interactive) components > Use interactive client components inside of bricks when using server components. When using the `react-bricks/rsc` library in a Server Components starter, if you have interactive bricks, which need client hydration, you need to create 2 components: a server wrapper and the client component, in this way: ```tsx title="Map.tsx" import { types, wrapClientComponent } from 'react-bricks/rsc' import { RegisterComponent } from 'react-bricks/rsc/client' import MapClient, { MapProps } from './MapClient' const MAPTILER_ACCESS_TOKEN = '' // Insert access token const schema: types.IBlockType<MapProps> = { name: 'map', label: 'Map', category: 'contact', tags: ['contacts', 'map'], playgroundLinkLabel: 'View source code on Github', playgroundLinkUrl: 'https://github.com/ReactBricks/react-bricks-ui/blob/master/src/website/Map/Map.tsx', previewImageUrl: `/bricks-preview-images/map.png`, getDefaultProps: () => ({ lat: '45.6782509', lng: '9.5669407', zoom: '6', }), sideEditProps: [ { name: 'zoom', label: 'Zoom', type: types.SideEditPropType.Number, }, { name: 'lat', label: 'Latitude', type: types.SideEditPropType.Number, }, { name: 'lng', label: 'Longitude', type: types.SideEditPropType.Number, }, { name: 'maptiler', label: 'MapTiler', type: types.SideEditPropType.Custom, show: () => !MAPTILER_ACCESS_TOKEN, component: () => { if (!MAPTILER_ACCESS_TOKEN) { return ( <p className="text-sm"> For better maps, please create a MapTiler free account and set the{' '} <code className="text-xs">MAPTILER_ACCESS_TOKEN</code> string. </p> ) } return null }, }, ], } export default wrapClientComponent({ ClientComponent: MapClient, RegisterComponent, schema, }) ``` ```tsx title="MapClient.tsx" 'use client' import { Map, Marker } from 'pigeon-maps' import { maptiler } from 'pigeon-maps/providers' import React from 'react' export interface MapProps { zoom: string lat: string lng: string mapTilerAccessToken: string } export const MapClient: React.FC<MapProps> = ({ lat = '45.6782509', lng = '9.5669407', zoom = '10', mapTilerAccessToken, }) => { const mapTilerProvider = React.useCallback( (x: number, y: number, z: number, dpr?: number | undefined) => maptiler(mapTilerAccessToken, 'streets')(x, y, z, dpr), [mapTilerAccessToken] ) let mapTilerProviderProp = {} if (mapTilerAccessToken) { mapTilerProviderProp = { provider: mapTilerProvider, } } return ( <Map center={[parseFloat(lat), parseFloat(lng)]} height={350} metaWheelZoom zoom={parseInt(zoom, 10)} {...mapTilerProviderProp} dprs={[1, 2]} metaWheelZoomWarning="Use ctrl + wheel to zoom!" attribution={false} > <Marker anchor={[parseFloat(lat), parseFloat(lng)]} /> </Map> ) } export default MapClient ``` # Use the docs in your AI assistant > Connect the React Bricks documentation to Claude and other AI assistants with our MCP server and llms.txt files. import { Tabs, TabItem } from '@astrojs/starlight/components' You can plug the React Bricks documentation straight into your AI assistant, so it can search and read the docs while it helps you build. We offer two ways to do this: a **remote MCP server** (best — gives the assistant live search + fetch tools) and **`llms.txt` files** (plain-text docs any tool can ingest). ## MCP server The Model Context Protocol (MCP) server lets compatible assistants search the docs and pull in exactly the pages they need. **Endpoint** ``` https://docs.reactbricks.com/mcp ``` It exposes two tools: - `search_reactbricks_docs` — full-text search across the documentation - `get_reactbricks_doc` — fetch a page (or a single section) as clean Markdown ### Add it to Claude <Tabs> <TabItem label="Claude Code"> ```bash claude mcp add --transport http reactbricks-docs https://docs.reactbricks.com/mcp ``` </TabItem> <TabItem label="Claude Desktop"> Add this to your `claude_desktop_config.json` (Settings → Developer → Edit Config), then restart Claude Desktop: ```json { "mcpServers": { "reactbricks-docs": { "type": "http", "url": "https://docs.reactbricks.com/mcp" } } } ``` </TabItem> <TabItem label="Cursor / others"> Most MCP-compatible clients accept a Streamable HTTP server. Point them at: ``` https://docs.reactbricks.com/mcp ``` </TabItem> </Tabs> Once connected, try asking: _"Using the React Bricks docs, how do I create a nested repeater of bricks?"_ ## llms.txt If your tool doesn't support MCP, we also publish the docs as plain text following the [llms.txt](https://llmstxt.org/) convention: - [`/llms.txt`](https://docs.reactbricks.com/llms.txt) — overview + index - [`/llms-full.txt`](https://docs.reactbricks.com/llms-full.txt) — the complete documentation - [`/llms-small.txt`](https://docs.reactbricks.com/llms-small.txt) — a compact version Paste any of these into an AI chat, or point a tool at the URL, to give it the full context of the React Bricks documentation. # React Bricks Documentation > Guides, resources, and API references to help you build with React Bricks, the visual headless CMS for React.