Creating a visual page builder has become essential for modern web applications. Whether you're building a CMS, a website builder, or just want to give users more control over their content, a drag-and-drop interface can significantly improve the user experience. In this comprehensive guide, we'll walk through building a powerful page builder using the @dndbuilder.com/react
package.
What We'll Build
By the end of this tutorial, you'll have a fully functional page builder that includes:
🖱️ Drag-and-drop interface for arranging content blocks
🧩 Custom blocks with editable properties
🎨 Visual controls for styling and configuration
💾 Content persistence and rendering
📱 Responsive design capabilities
Why Choose @dndbuilder.com/react?
The @dndbuilder.com/react
package stands out because it offers:
- Block-based architecture that's easy to understand and extend
- Built-in undo/redo functionality powered by Redux
- Responsive design tools for mobile-first development
- Extensible API for creating custom blocks and controls
- Server-side rendering support for production applications
- Tree-shakable imports to keep your bundle size minimal
Getting Started
Installation
First, let's install the package and its dependencies:
npm install @dndbuilder.com/react
# or
yarn add @dndbuilder.com/react
# or
pnpm add @dndbuilder.com/react
Quick Start
Create a basic editor component to get started:
import React, { useState } from "react";
import { Editor, BuilderProvider, store } from "@dndbuilder.com/react";
import "@dndbuilder.com/react/dist/style.css";
const editorConfig = {
blocks: [], // We'll add blocks here
};
function App() {
const [initialContent, setInitialContent] = useState({});
return (
<BuilderProvider store={store}>
<div className="app-container">
<Editor
content={initialContent}
builderConfig={editorConfig}
/>
</div>
</BuilderProvider>
);
}
export default App;
That's it! Now, you will able to see the drag and drop editor in your application.
Understanding Core Concepts
Before diving into custom blocks, let's understand the key concepts:
1. 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.
2. Blocks
Blocks are the building units of your pages. Each block represents a specific type of content (heading, paragraph, image, etc.).
3. Controls
Controls provide the interface for users to configure block properties like text, colors, spacing, and other styling options.
4. Store
The store manages the editor's state, including content structure, selected blocks, and undo/redo history.
5. Settings
Settings contain the configuration data for each block instance.
Working with Content
Saving Content
Use the useContent hook to save content as shown in the documentation:
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 exactly as documented:
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>
);
}
Creating Your First Custom Block
Let's create a simple block that includes a title and a description.
To create a custom block, you need to:
- Create a component for your block
- Create a control component to control block's property. (Optional)
- Define the block configuration using
createBlockConfig
utility - Include the block in your editor configuration
Here's a simplified example of creating a custom block:
//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;
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>
);
};
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;
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 existing blocks by extending their configuration, as shown in the documentation:
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...
],
};
Conclusion
The @dndbuilder.com/react
package provides a robust foundation for building drag-and-drop page builders. By following the patterns and examples from this article, you can create powerful, customizable page builders that provide excellent user experiences.
The key is to start with the basic setup, understand the core concepts, and gradually build complexity by adding custom blocks and advanced features. The package's extensible architecture makes it easy to scale from simple use cases to complex, production-ready applications.
Next Steps
- Explore the comprehensive documentation for more advanced features
- Contact support at support@dndbuilder.com for help with specific use case
Top comments (0)