A powerful drag-and-drop page builder for React applications. This package provides a comprehensive set of components, hooks, and utilities for building customizable page editors with a block-based approach.
- @dndbuilder.com/react
- 🧩 Block-Based Architecture: Build pages using pre-defined or custom blocks
- 🖱️ Drag and Drop Interface: Intuitive drag-and-drop functionality using React DND
- 🔄 Undo/Redo Support: Built-in history management with Redux Undo
- 📱 Responsive Design: Create responsive layouts that work across devices
- 🎨 Customizable UI: Extensive styling options with Tailwind CSS
- 🧰 Extensible API: Easily extend with custom blocks and functionality
- 🔌 Plugin System: Support for third-party plugins and extensions
- 📦 Tree-Shakable: Import only what you need
- 🌐 Server-Side Rendering: Compatible with Next.js for SSR
- 🔍 TypeScript Support: Fully typed with TypeScript for better development experience
- 🎨 Theme Support: Built-in theming system for consistent styling across your application
# Using npm
npm install @dndbuilder.com/react
# Using yarn
yarn add @dndbuilder.com/react
# Using pnpm
pnpm add @dndbuilder.com/react
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;
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 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 are UI components that allow users to configure block settings. They provide interfaces for adjusting properties like text, colors, spacing, and other styling options.
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.
The package exports several components for building and rendering pages:
-
Editor
: The main editor component -
BuilderProvider
: Provider component for the editor state
import { Editor, BuilderProvider } from "@dndbuilder.com/react";
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";
Custom hooks for accessing and manipulating the editor state:
-
useContent
: Access and update the content state -
useBuilderSelector
: Select blocks and manage selection state -
useBuilderDispatch
: Dispatch actions to the editor store -
useSettings
: Access and update editor settings -
useFieldName
: Generate settings field names -
useAction
: Access editor actions like save, copy, paste, undo, redo, and panel management -
useTheme
: Access and update the current theme
import {
useContent,
useBuilderSelector,
useBuilderDispatch,
useSettings,
useFieldName,
useTheme,
} from "@dndbuilder.com/react/hooks";
Utility functions for working with blocks and content:
-
createBlockConfig
: Create a block configuration -
createId
: Generate unique IDs for blocks -
generateResponsiveStyles
: Generate responsive styles for blocks -
generatePsuedoStyles
: Generate pseudo styles for blocks -
generateTypography
: Generate typography styles -
generateSpacing
: Generate spacing styles -
generateUnitValue
: Generate unit values for styles -
generateBoxShadow
: Generate box shadow styles -
generateBackground
: Generate background styles
import {
createBlockConfig,
createId,
generateResponsiveStyles,
generatePsuedoStyles,
generateTypography,
generateSpacing,
generateUnitValue,
generateBoxShadow,
generateBackground,
} from "@dndbuilder.com/react/utils";
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>;
}
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>
);
}
To create a custom block, you need to:
- Create a component for your block
- Define the block configuration using
createBlockConfig
utility - 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...
],
};
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...
],
};
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",
},
},
};
},
});
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.
A theme consists of the following properties:
-
id
: A unique identifier for the theme -
name
: A human-readable name for the theme -
settings
: An object containing the theme settings
The theme settings include:
-
layout
: Container width, padding, and gap settings -
color
: Accent color, background color, text color, and color presets -
typography
: Typography settings for body text and headings -
button
: Button styling including typography, colors, borders, and shadows -
link
: Link styling including colors and typography -
form
: Form element styling including labels and inputs -
customCss
: Custom CSS to be applied globally
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>;
}
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>;
}
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 },
};
}
- 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.
Need help with @dndbuilder.com/react? We're here to assist you.
- Documentation: Start with this README and visit our comprehensive documentation
- Email Support: Reach out to our support team at support@dndbuilder.com
- Bug Reports: Report issues through our Github Repo
For more information, visit dndbuilder.com.