Introduction
Wouldn't it be cool to code a website builder powered by React?
How would you even start?
It would be nice to have some sort of library upon which you could code your website editor with total freedom to implement whatever feature suiting your needs. Build UI lets you do just that. 🙌💪
Overview 🔎
Build-UI is a library thought for React developers packed with features that allow you to effortlessly create website builders. It ships with drag and drop functionality, undo-redo logic, site serialization and deserialization along with some other interesting tools out of the box. Because of the way it is built, it also supports other features such as SSR and SSG, component dynamic loading, touch support for drag and drop functionality, and more, without you having to worry about hacking your way around.
Installation 💻
You can install via npm with the command:
npm install --save build-ui
Demo 🕹️
You can go check out this cool demo we set up to show some of the features you can implement with Build UI.
Tutorial
We'll create a very simple dummy website editor. For a better and more thorough tutorial you can refer to the docs. (I would still recommend going through the tutorial in the docs to understand Build UI better).
Behold, here's a preview of what we are going to be building:
It looks simple right? Trust me, the code is going to be simple too.
As you can see, we have a small Section where we can drop our Alert buttons from a single-button Toolbar. Simple, but it is essentially what all page builders do.
No more talking, let's jump into the code:
We'll start with that Alert
Component:
const Alert = ({
message,
text,
...rest
}) => {
const handleAlert = () => {
alert(message);
}
return <button
onClick = {handleAlert}
{...rest}
>
{text}
</button>
}
All good, not much to see up here.
Now, with Build UI you create some special components named 'View Components', which wrap the components you add to your page (in this case our Alert
). Let's see an example of a view component:
import {DnDBuilder, useEditor} from 'build-ui';
import Alert from './Alert';
const AlertView = ({
id,
...props
}) => {
const editor = useEditor({
id: id
});
return <DnDBuilder
onDragStart = {editor.handleDragStart}
onDragEnd = {editor.handleDragEnd}
draggable = {true}
>
<Alert {...props} />
</DnDBuilder>
}
So what's going on here?
As you can see, your view component will be injected with some props: an id and some props that your Alert
Component will receive (Don't worry too much about this yet, we will later see more on this). In our View Component, we add that extra layer of logic needed for our website builder. This is great because it uses one of React's main features: composition.
Build UI ships with a special hook, called useEditor
, that receives the id prop that you were passed in the component and in return, delivers a bag of useful functions that you can use for your site building logic. Here we defined a draggable view component, which means you can drag the component and drop it elsewhere. We could also define a view component to be a droppable component, where you can drop other components, with the handleDrop
function we also receive from the editor. This is precisely what we do in our SectionView
, with our Section
that simply renders a div with some styles (Not recommending inline styles, by the way):
const Section = props => {
return <div
style = {{
width: 600,
height: 300,
backgroundColor: '#eeebf2'
}}
{...props}
/>
}
import {DnDBuilder, useEditor} from 'build-ui';
import Section from './Section';
const SectionView = ({
id,
...props
}) => {
const editor = useEditor({
id: id
});
return <DnDBuilder
onDrop = {editor.handleDrop}
>
<Section {...props} />
</DnDBuilder>
}
You may have also noticed the DnDBuilder
Component in which we wrapped our Alert
. This is a component to which we pass drag-and-drop events. To us, it looks like a good old div element. In fact, it does render as a div element. But internally, DnDBuilder
handles all drag and drop operations, including Touch Support, without us having to worry about its implementation.
Now, that Toolbar button down there... How it that coded? It uses Build UI's useTools
hook. Build-UI supports drag and drop operations so you can interact with your site builder in that way. Let's take a look at the AlertTools
:
import {DnDBuilder, useTools, item, branch} from 'build-ui';
const AlertTools = () => {
const tools = useTools();
const handleDragTool = () => {
const alertProps = {
message: 'How is it going, folk?',
text: 'Greet me',
}
const alert = item({
type: 'Alert',
props: alertProps
});
const data = branch(alert);
tools.triggerDragStart({
data: data,
});
}
return <DnDBuilder
onDragStart = {handleDragTool}
onDragEnd = {tools.handleDragEnd}
draggable = {true}
as = 'button'
>
Alert
</DnDBuilder>
}
Notice how we used a branch
and item
functions? Where did this came from and what are they used for? They are a couple of utility function shipped with Build-UI that allow you to define structures of what will be added to the site builder. This is where you define the type of what will be added to the builder, which should always be a string (most likely the name of your end component, like Alert), and the props your view component will be passed initially. Notice how we also used the triggerDragStart function to start dragging our Alert
in our handler.
We are ready to look at what really glues everything together. It is the Builder
Component, in which we will wrap our site builder.
We will kick off our initial website builder with the Section
component we defined earlier where we will be able to drag stuff, such as hundreds of our alerts!!
import {Builder, Workspace, item, branch} from "build-ui"
import AlertTools from "./ui/alert/AlertTools";
import AlertView from "./ui/alert/AlertView";
import SectionView from "./ui/section/SectionView";
const MyBuilder = () => {
const section = item({
type: 'Section',
props: {},
});
const tree = branch(section);
const view = {
Section: SectionView,
Alert: AlertView,
}
return <Builder initialTree = {tree}>
<Workspace view = {view} />
<AlertTools />
</Builder>
}
Remember we used a type string when we created our Alert
in the AlertTools
? We do the same here for our the Section
in our initial tree. And as you can probably notice, the view object above uses these type strings as keys, to know that to render to the screen.
Et voilà. We have finished creating a very (very) simple page editor where we can drag and drop limitless alerts to our page. How cool is that? Well, not much, really 😛😅. But we are sure you can come up with, and start building much more interesting page builders.
And... "where's the redo-undo, site serialization and all that other stuff you promised"? Take a look at the tutorial in the official documentation, you'll see how easy it is to use those features too.
Repository 🗃️
Visit the repository to know more about the project. I will be glad to have you around 😊. You will find links to the documentation in the project's README.md. I will happy to receive any feedback.
Further Notes 📓
This is an early stage project, so any feedback/suggestions are welcome. If you would like to contribute to the project, contact me. It would be more than awesome to start a community.
Top comments (8)
Hello Luis, I am currently exploring the usage of build-ui. Is it possible to import a npm package, and make its elements drag and droppable ?
Hi Habib, thanks for taking the time to look around!! Yes, it is totally possible. There is an example on this in the demo, where I took Material-UI components (a button, a grid) and made them draggable/droppable. I think it would be a good idea to check out the source code in the repository. I can link you to the code: github.com/LuisMPS/build-ui/tree/m...
Hello Luis, is it possible to get your email to discuss the package further ?
Hi! Sure, please follow me back so I can send you my email on a DM.
done !
Oops, I can't find the way to send DMs. I think I'll just put my email on my profile :)
hey thanks for this tutorial but one more thing i want to ask it's possible add custom domain to each page created in my web ??
Hi krazyd!
Do you mean a custom route for each page? If you did mean domain, I think you'd have to buy a domain from a domain provider, which is a bit unrelated to BuildUI 😅