Documentation
Everything you need to know about how to build amazing drag-and-drop interfaces with DnD Builder
Installation
This package is published to npm and can be installed directly without any additional authentication.
Install the Package
Simply run one of the following commands in your project:
# Using npm
npm install @dndbuilder.com/react
# Using yarn
yarn add @dndbuilder.com/react
# Using pnpm
pnpm add @dndbuilder.com/react
No additional configuration or authentication tokens are required.
Quick Start
import React, { useState } from "react";
import { Editor, BuilderProvider } from "@dndbuilder.com/react";
import { store } from "@dndbuilder.com/react";
import "@dndbuilder.com/react/dist/style.css";
// Basic editor configuration
const editorConfig = {
blocks: [], // Your blocks will go here
// Other configuration options
};
function App() {
// Optional: Initial content for the editor
const [initialContent, setInitialContent] = useState({});
return (
<BuilderProvider store={store}>
<Editor content={initialContent} builderConfig={editorConfig} />
</BuilderProvider>
);
}
export default App;
Core Concepts
Editor
The Editor is the main component that provides the drag-and-drop interface for building pages. It manages the state of the page content and provides tools for editing blocks.
Blocks
Blocks are the building blocks of pages. Each block represents a specific type of content, such as headings, paragraphs, images, or more complex components like testimonials or pricing tables.
Controls
Controls are UI components that allow users to configure block settings. They provide interfaces for adjusting properties like text, colors, spacing, and other styling options.
Store
The store manages the state of the editor, including the content structure, selected blocks, and undo/redo history. It's built on Redux and provides a predictable state container.
API Reference
Components
The package exports several components for building and rendering pages:
Editor: The main editor componentBuilderProvider: Provider component for the editor state
import { Editor, BuilderProvider } from "@dndbuilder.com/react";
Server Components
For server-side rendering, you can use the RenderContent component to render content fetched from your backend
import { RenderContent } from "@dndbuilder.com/react/components/server";
Hooks
Custom hooks for accessing and manipulating the editor state:
useContent: Access and update the content stateuseBuilderSelector: Select blocks and manage selection stateuseBuilderDispatch: Dispatch actions to the editor storeuseSettings: Access and update editor settingsuseFieldName: Generate settings field namesuseAction: Access editor actions like save, copy, paste, undo, redo, and panel management
import {
useContent,
useBuilderSelector,
useBuilderDispatch,
useSettings,
useFieldName,
useAction,
} from "@dndbuilder.com/react/hooks";
Utilities
Utility functions for working with blocks and content:
createBlockConfig: Create a block configurationcreateId: Generate unique IDs for blocksgenerateResponsiveStyles: Generate responsive styles for blocksgeneratePsuedoStyles: Generate pseudo styles for blocksgenerateTypography: Generate typography stylesgenerateSpacing: Generate spacing stylesgenerateUnitValue: Generate unit values for stylesgenerateBoxShadow: Generate box shadow stylesgenerateBackground: Generate background styles
import {
createBlockConfig,
createId,
generateResponsiveStyles,
generatePsuedoStyles,
generateTypography,
generateSpacing,
generateUnitValue,
generateBoxShadow,
generateBackground,
} from "@dndbuilder.com/react/utils";
Working with Content
Saving Content
To save content, you can use the useContent hook to access the editor state:
import { useContent } from "@dndbuilder.com/react/hooks";
function SaveButton() {
const { content, saveContent } = useContent();
const handleSave = async () => {
// Save content to your backend or local storage
try {
await fetch("/api/save-content", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content }),
});
saveContent(); // Mark content as saved
} catch (error) {
console.error("Failed to save content:", error);
}
};
return <button onClick={handleSave}>Save Content</button>;
}
Rendering Content
To render content on the frontend, use the RenderContent component:
import { RenderContent } from "@dndbuilder.com/react/components/server";
import { editorConfig } from "./editorConfig"; // Your editor configuration
async function ContentPage() {
// Fetch content from your backend
const response = await fetch("/api/get-content");
const { content } = await response.json();
return (
<div className="page-container">
<RenderContent content={content} builderConfig={editorConfig} />
</div>
);
}
Customization
Creating Custom Blocks
To create a custom block, you need to:
- Create a component for your block
- Define the block configuration using
createBlockConfigutility - Include the block in your editor configuration
Here's a simplified example of creating a custom block:
// 1. Create your block component (my-block.tsx)
import React from "react";
import { BlockProps } from "@dndbuilder.com/react/types";
const MyBlock = ({ settings, meta }: BlockProps) => {
return (
<div className="my-custom-block">
<h3>{settings.title}</h3>
<p>{settings.description}</p>
</div>
);
};
export default MyBlock;
// 2. Create a control component (my-block-control.tsx)
import React from "react";
import { ControlProps } from "@dndbuilder.com/react/types";
import { TextInput } from "@dndbuilder.com/react/components";
const MyBlockControl = ({ settings, updateSettings }: ControlProps) => {
return (
<div className="control-panel">
<TextInput
label="Title"
value={settings.title || ""}
onChange={(value) => updateSettings({ title: value })}
/>
<TextInput
label="Description"
value={settings.description || ""}
onChange={(value) => updateSettings({ description: value })}
/>
</div>
);
};
export default MyBlockControl;
// 3. Define your block configuration (my-block.config.ts)
import { createBlockConfig } from "@dndbuilder.com/react/utils";
import { lazy } from "react";
import { FiBox } from "react-icons/fi";
const MyBlockConfig = createBlockConfig({
type: "my-block",
label: "My Custom Block",
icon: FiBox,
component: lazy(() => import("./my-block")),
isVisible: () => true,
group: "Custom",
settings: {
title: "Default Title",
description: "Default description text",
},
controls: [
{
label: "Content",
component: lazy(() => import("./my-block-control")),
},
],
});
export default MyBlockConfig;
// 4. Include the block in your editor configuration
import MyBlockConfig from "./blocks/my-block/my-block.config";
export const editorConfig = {
blocks: [
MyBlockConfig,
// Other blocks...
],
};
Overriding Existing Blocks
You can override the configuration of an existing block by extending it:
import { BlockType } from "@dndbuilder.com/react/types";
import { createBlockConfig } from "@dndbuilder.com/react/utils";
import { lazy } from "react";
// Override the Heading block configuration
const CustomHeadingConfig = createBlockConfig({
type: BlockType.HEADING, // Use the existing block type
component: lazy(() => import("./components/custom-heading.block")),
// Override other properties as needed
controls: [
{
label: "Custom Style",
component: lazy(() => import("./components/custom-heading-style.control")),
},
],
});
// Include the overridden block in your editor configuration
export const editorConfig = {
blocks: [
CustomHeadingConfig,
// Other blocks...
],
};
Styling
You can customize the appearance of blocks by:
- Using the built-in style controls
- Providing custom CSS classes
- Implementing custom style functions
// Custom style function example
const MyBlockConfig = createBlockConfig({
// ...other configuration
style: ({ settings, breakpoints }) => {
return {
"& .my-custom-block": {
backgroundColor: settings.backgroundColor,
padding: `${settings.padding}px`,
borderRadius: `${settings.borderRadius}px`,
// Add responsive styles
[breakpoints.md]: {
flexDirection: "row",
},
[breakpoints.sm]: {
flexDirection: "column",
},
},
};
},
});
Theming
The package provides a comprehensive theming system that allows you to customize the appearance of your application. Themes can be used to define colors, typography, spacing, and other visual aspects of your application.
Theme Structure
A theme consists of the following properties:
id: A unique identifier for the themename: A human-readable name for the themesettings: An object containing the theme settings
The theme settings include:
layout: Container width, padding, and gap settingscolor: Accent color, background color, text color, and color presetstypography: Typography settings for body text and headingsbutton: Button styling including typography, colors, borders, and shadowslink: Link styling including colors and typographyform: Form element styling including labels and inputscustomCss: Custom CSS to be applied globally
Using Themes
You can access and update the current theme using the useTheme hook:
import { useTheme } from "@dndbuilder.com/react/hooks";
function ThemeToggle() {
const [theme, setTheme] = useTheme();
const toggleDarkMode = () => {
setTheme({
...theme,
settings: {
...theme.settings,
color: {
...theme.settings.color,
backgroundColor:
theme.settings.color.backgroundColor === "#ffffff" ? "#1a1a1a" : "#ffffff",
textColor: theme.settings.color.textColor === "#1a1a1a" ? "#ffffff" : "#1a1a1a",
},
},
});
};
return <button onClick={toggleDarkMode}>Toggle Dark Mode</button>;
}
Saving Themes
To save a theme, you can use the same approach as saving content:
import { useTheme } from "@dndbuilder.com/react/hooks";
function SaveThemeButton() {
const [theme] = useTheme();
const handleSave = async () => {
try {
await fetch("/api/save-theme", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ theme }),
});
console.log("Theme saved successfully");
} catch (error) {
console.error("Failed to save theme:", error);
}
};
return <button onClick={handleSave}>Save Theme</button>;
}
Advanced Usage
Server-Side Rendering
The package supports server-side rendering (SSR) with Next.js.
// Next.js page component
import { RenderContent } from "@dndbuilder.com/react/components/server";
import { editorConfig } from "../editorConfig"; // Your editor configuration
export default function Page({ content }) {
return <RenderContent content={content} builderConfig={editorConfig} />;
}
// Server-side data fetching
export async function getServerSideProps() {
const response = await fetch("https://api.example.com/content");
const content = await response.json();
return {
props: { content },
};
}
Troubleshooting
Common Issues
- Block not rendering: Ensure the block component is correctly registered in the editor configuration.
- Styling issues: Check your CSS classes and ensure they are applied correctly.
- Type errors: Verify that your TypeScript types match the expected interfaces.