How to implement editable regions for custom component in React with SDK Gen 2

Thanks for your helpful reply. Actually I managed to make it work now after taking some time looked deeper into the source code and it’s props definition. It turns out that I wasn’t passing necessary props to the <Blocks /> component. I guess I’ll share my code here so that if anyone having the same issue can learn from my mistake.

IMPORTANT: if you have isRSC: true in any custom component, <Blocks /> can only be used in RSC because of passing builderComponents to registeredComponents props. Workaround to use <Blocks /> in client component is to pass it as props like my example below. More info: Rendering: Composition Patterns | Next.js (nextjs.org)

BurgerButton.tsx:

import { Blocks, BuilderBlock, RegisteredComponent } from '@builder.io/sdk-react-nextjs';
import { BurgerProps, DrawerProps, MantineSize } from '@mantine/core';

import { BurgerButtonClient } from './BurgerButtonClient';
import { CSSProperties, FunctionComponent, ReactNode } from 'react';
import { BuilderContext } from '../../types/builder';

export interface BuilderBlockAttributes {
	className?: string;
	href?: string;
	style?: CSSProperties;
}

// copy from '../../types/builder'
export type BuilderBlockProps<
	P = unknown,
	L extends { href?: string; children?: ReactNode } = { href?: string; children?: ReactNode },
> = P & {
	attributes?: BuilderBlockAttributes;
	builderBlock: BuilderBlock;
	builderContext: BuilderContext;
	builderLinkComponent?: FunctionComponent<L>;
	builderComponents: Record<string, RegisteredComponent>;
	children?: ReactNode;
};

interface BurgerButtonProps extends BurgerProps {
	blocks?: BuilderBlock[];
	drawerProps?: Omit<DrawerProps, 'offset'> & {
		offset?: {
			top?: number;
			right?: number;
			bottom?: number;
			left?: number;
		};
		size?: MantineSize;
	};
}

export const BurgerButton = ({
	attributes,
	blocks,
	// these props are passed by Builder when this component is used in Visual Editor
	builderBlock,
	builderComponents,
	builderContext,
	builderLinkComponent,
	// end
	color,
	drawerProps,
	lineSize,
	size,
}: BuilderBlockProps<BurgerButtonProps>) => {
	return (
		<BurgerButtonClient
			attributes={attributes}
			color={color}
			drawerProps={drawerProps}
			lineSize={lineSize}
			size={size}
		>
			<Blocks
				blocks={blocks}
				context={builderContext} // was missing
				linkComponent={builderLinkComponent}  // was missing, not necessary if you don't use linkComponent prop on <Content />
				parent={builderBlock.id}
				path='component.options.blocks'
				registeredComponents={builderComponents}  // was missing
			/>
		</BurgerButtonClient>
	);
};

BurgerButtonClient.tsx:

'use client';

import { Burger, BurgerProps, Drawer, DrawerProps } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { omit } from 'lodash';

import { BuilderBlockProps } from '../../types/builder';

interface BurgerButtonClientProps extends Pick<BuilderBlockProps, 'attributes' | 'children'>, BurgerProps {
	drawerProps?: Omit<DrawerProps, 'offset'> & {
		offset?: {
			top?: number;
			right?: number;
			bottom?: number;
			left?: number;
		};
	};
}

export const BurgerButtonClient = ({
	attributes,
	children,
	color,
	drawerProps,
	lineSize,
	size,
}: BurgerButtonClientProps) => {
	const [opened, { toggle, close }] = useDisclosure();

	const { bottom, left, right, top } = drawerProps?.offset ?? {};

	return (
		<>
			<Burger
				{...attributes}
				color={color}
				lineSize={lineSize}
				onClick={toggle}
				opened={opened}
				size={size}
			/>
			<Drawer
				{...omit(drawerProps, 'offset')}
				onClose={close}
				opened={opened}
				overlayProps={{
					bottom,
					left,
					right,
					top,
				}}
				styles={{
					inner: {
						bottom,
						left,
						right,
						top,
					},
				}}
			>
				{children}
			</Drawer>
		</>
	);
};

BurgerButton.register.ts:

import { RegisteredComponent } from '@builder.io/sdk-react-nextjs';

import { BurgerButton } from './BurgerButton';

const BurgerButtonEntry: RegisteredComponent = {
	component: BurgerButton,
	name: 'BurgerButton',
	noWrap: true,
	isRSC: true,
	inputs: [
		{
			name: 'color',
			type: 'string',
		},
		{
			name: 'lineSize',
			type: 'number',
			helperText: 'Line size in pixel',
		},
		{
			name: 'size',
			type: 'string',
		},
		{
			name: 'drawerProps',
			type: 'object',
			friendlyName: 'Drawer options',
			subFields: [
				{
					name: 'offset',
					type: 'object',
					subFields: [
						{ name: 'top', type: 'number' },
						{ name: 'right', type: 'number' },
						{ name: 'bottom', type: 'number' },
						{ name: 'left', type: 'number' },
					],
				},
				{ name: 'position', type: 'string', enum: ['left', 'right', 'top', 'bottom'], defaultValue: 'left' },
				{ name: 'withCloseButton', type: 'boolean', defaultValue: false },
			],
		},
		{
			name: 'blocks',
			type: 'uiBlocks',
			hideFromUI: true,
			defaultValue: []
		},
	],
};

export { BurgerButtonEntry as BurgerButton };

I really think the documentation should’ve mention this usage somewhere. I hope when @builder.io/sdk-react-nextjs become stable there is an example like mine included in the documentation.

Thanks again for looking into my problem.