DEV Community

Bryntum for Bryntum

Posted on • Edited on

Building a Trello Clone with Bryntum TaskBoard

Trello is one of the most commonly used project management applications. And why shouldn't it be? With its intuitive design and easy-to-use interface, Trello makes project management effortless. You can easily drag and drop tasks and move them to different columns.

But what if there was a solution where you could build your own Trello clone in minutes? The Bryntum TaskBoard can do just that. It's a perfect component that provides the features you can use to create a project management application like Trello. It has a pure JavaScript implementation that you can integrate with popular frontend libraries and frameworks, including React and Vue.js.

In this tutorial, you'll learn how to build a project management application like Trello using React and Bryntum TaskBoard. You'll start with a basic React application and work through the code examples to create a fully functional project management application.

Building a Trello-like Application Using Bryntum TaskBoard

Before you begin this tutorial, you'll need Node.js version 14 or newer as well as npm version 6 or newer installed on your computer. You'll also need a code editor like Visual Studio Code.

You can follow along with this tutorial using this GitHub repository.

Set Up the Project

To begin, run the following command to create a new React project _trello-with-bryntum_ using create-react-app:

npx create-react-app trello-with-bryntum
Enter fullscreen mode Exit fullscreen mode

Change the directory to the newly created project:

cd trello-with-bryntum
Enter fullscreen mode Exit fullscreen mode

Once the directory has been updated, you need to disable the React StrictMode to use Bryntum components, as this feature is currently under development. Remove <React.StrictMode> from src/index.js:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: <https://bit.ly/CRA-vitals>
reportWebVitals();
Enter fullscreen mode Exit fullscreen mode

Install Bryntum TaskBoard

To install Bryntum TaskBoard, you need to sign up for a free trial. Bryntum serves the TaskBoard component from a private registry, so you need to specify the registry URL to npm using the following command:

npm config set "@bryntum:registry=https://npm.bryntum.com"
Enter fullscreen mode Exit fullscreen mode

Since Bryntum's registry is authenticated, you'll need to log in using the credentials you signed up with:

npm login --registry=https://npm.bryntum.com
Enter fullscreen mode Exit fullscreen mode

Please note: The "@" symbol should be replaced with ".." in the login email. For example, "someone@example.com" will become "someone..example.com". Use "trial" as the password.

Now, run the following command to install the Bryntum TaskBoard dependencies:

npm i @bryntum/taskboard@npm:@bryntum/taskboard-trial@^5.1.2 @bryntum/taskboard-react@5.1.2
Enter fullscreen mode Exit fullscreen mode

Add TaskBoard Configuration

To add TaskBoard configuration, create a new folder public/users/ inside the project. Then download the user images and add them to this folder. This allows the application to access these images even in a production environment.

Create a new file called src/AppConfig.js and export the taskBoardConfig object that provides a list of column names, the column name mapping field status, and the path to resource images:

export const taskBoardConfig = {
  // Url for resource avatar images
  resourceImagePath: "users/",
  // default columns
  columns: ["todo", "doing", "done"],
  // Field used to pair a task to a column
  columnField: "status",
};
Enter fullscreen mode Exit fullscreen mode

Then create a new file called src/AppData.js and export the application's default data. This example uses a static file, but you can also use an API endpoint or database to fetch this if you prefer:

Note: The user.image should match a file name from the public/users/ folder.

export const projectData = {
  tasks: [
    { id: 1, name: "Book flight", status: "done", prio: "medium" },
    { id: 2, name: "Book hotel", status: "done", prio: "medium" },
    { id: 3, name: "Pack bags", status: "doing", prio: "low" },
    { id: 4, name: "Get visa", status: "doing", prio: "high" },
    { id: 5, name: "Book train", status: "done", prio: "medium" },
    { id: 6, name: "Go to airport", status: "todo", prio: "low" },
    { id: 7, name: "Renew passport", status: "todo", prio: "high" },
    { id: 8, name: "Swim in pool", status: "todo", prio: "medium" },
    { id: 9, name: "Scuba diving", status: "todo", prio: "medium" },
    { id: 10, name: "Canyoning", status: "todo", prio: "low" },
    { id: 11, name: "Snorkeling", status: "doing", prio: "medium" },
    { id: 12, name: "Diving license", status: "todo", prio: "medium" },
    { id: 13, name: "Book cab", status: "done", prio: "low" },
    { id: 14, name: "Write postcards", status: "todo", prio: "medium" },
    { id: 15, name: "Take pictures", status: "todo", prio: "low" },
    { id: 16, name: "Take selfies", status: "todo", prio: "high" },
    { id: 17, name: "Post on instagram", status: "todo", prio: "medium" },
    { id: 18, name: "Call grandma", status: "todo", prio: "medium" },
    { id: 19, name: "Buy swimming ring", status: "done", prio: "high" },
    { id: 20, name: "Get in shape", status: "doing", prio: "medium" },
    { id: 21, name: "Iron shirts", status: "done", prio: "low" },
  ],
  users: [
    { id: 1, name: "Angelo", image: "angelo.jpg" },
    { id: 2, name: "Celia", image: "celia.jpg" },
    { id: 3, name: "Dave", image: "dave.jpg" },
    { id: 4, name: "Emilia", image: "emilia.jpg" },
    { id: 5, name: "Gloria", image: "gloria.jpg" },
    { id: 6, name: "Henrik", image: "henrik.jpg" },
    { id: 7, name: "Kate", image: "kate.jpg" },
    { id: 8, name: "Lee", image: "lee.jpg" },
    { id: 9, name: "Lisa", image: "lisa.jpg" },
    { id: 10, name: "Mark", image: "mark.jpg" },
    { id: 11, name: "Steve", image: "steve.jpg" },
  ],
  assignments: [
    { id: 1, event: 7, resource: 1 },
    { id: 2, event: 7, resource: 2 },
    { id: 3, event: 8, resource: 2 },
    { id: 4, event: 4, resource: 3 },
    { id: 5, event: 7, resource: 3 },
    { id: 6, event: 7, resource: 4 },
    { id: 7, event: 7, resource: 5 },
    { id: 8, event: 7, resource: 6 },
    { id: 9, event: 7, resource: 7 },
    { id: 10, event: 7, resource: 8 },
    { id: 11, event: 7, resource: 9 },
    { id: 12, event: 7, resource: 10 },
    { id: 13, event: 7, resource: 11 },
    { id: 14, event: 16, resource: 7 },
    { id: 15, event: 16, resource: 8 },
    { id: 16, event: 16, resource: 9 },
    { id: 17, event: 16, resource: 10 },
    { id: 18, event: 16, resource: 11 },
    { id: 19, event: 19, resource: 10 },
    { id: 20, event: 9, resource: 7 },
    { id: 21, event: 12, resource: 8 },
    { id: 22, event: 14, resource: 9 },
    { id: 23, event: 17, resource: 10 },
    { id: 24, event: 18, resource: 10 },
    { id: 25, event: 11, resource: 9 },
    { id: 26, event: 20, resource: 8 },
    { id: 27, event: 1, resource: 7 },
    { id: 28, event: 2, resource: 6 },
    { id: 29, event: 5, resource: 5 },
    { id: 30, event: 6, resource: 4 },
    { id: 31, event: 10, resource: 3 },
    { id: 32, event: 15, resource: 2 },
    { id: 33, event: 3, resource: 1 },
    { id: 34, event: 13, resource: 2 },
    { id: 35, event: 21, resource: 3 },
    { id: 36, event: 8, resource: 3 },
    { id: 37, event: 17, resource: 9 },
    { id: 38, event: 17, resource: 8 },
    { id: 39, event: 17, resource: 7 },
    { id: 40, event: 17, resource: 6 },
  ],
};

Enter fullscreen mode Exit fullscreen mode

Use Bryntum TaskBoard

Now that the project configuration is ready, it's time to use the BryntumTaskBoard and BryntumProjectModel components inside the src/App.js to create a drag-and-drop project manager.

Import the taskBoardConfig from ./AppConfig.js, and projectData from the ./AppData.js files. Use the useRef hook to create a reference to the components and the useState hook to create individual states for the projectData:

// src/App.js
import React, { useRef, useState } from "react";
import {
  BryntumTaskBoard,
  BryntumProjectModel,
} from "@bryntum/taskboard-react";
import { taskBoardConfig } from "./AppConfig";
import { projectData } from "./AppData";
import "./App.css";

function App() {
  const taskBoard = useRef();
  const project = useRef();
  const [tasks] = useState(projectData.tasks);
  const [assignments] = useState(projectData.assignments);
  const [resources] = useState(projectData.users);
  return (
    <>
      <BryntumProjectModel
        ref={project}
        tasks={tasks}
        assignments={assignments}
        resources={resources}
      />
      <BryntumTaskBoard
        ref={taskBoard}
        project={project}
        {...taskBoardConfig}
      />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Please note: You must use the BryntumProjectModel as the first component in the tree to ensure BryntumTaskBoard works properly.

Run npm start to start the application and open http://localhost:3000 in a web browser:

TaskBoard without styling

At this point, the TaskBoard component will render, but it doesn't look like a board yet. To render the TaskBoard component correctly, you need to use one of the many themes that come with it. Remove all existing styles from src/App.css and import the material theme at the top of the file:

/* src/App.css */
@import '~@bryntum/taskboard/taskboard.material.css';
Enter fullscreen mode Exit fullscreen mode

TaskBoard with material theme

Add New Column Functionality

Now that the basic TaskBoard is ready, you need to add a header at the top with a button to add a new column. The button will use the prompt API to ask for the new column name and then add the new column by using the taskBoard ref and calling the columns.add method on it:

// src/App.js
import React, { useRef, useState } from "react";
import {
  BryntumTaskBoard,
  BryntumProjectModel,
} from "@bryntum/taskboard-react";
import { taskBoardConfig } from "./AppConfig";
import { projectData } from "./AppData";
import "./App.css";

function App() {
  const taskBoard = useRef();
  const project = useRef();
  const [tasks] = useState(projectData.tasks);
  const [assignments] = useState(projectData.assignments);
  const [resources] = useState(projectData.users);
  return (
    <>
      <BryntumProjectModel
        ref={project}
        tasks={tasks}
        assignments={assignments}
        resources={resources}
      />
      <nav className={"header"}>
        <h1 className={"heading"}>Trello using Bryntum TaskBoard</h1>
        <button
          className={"add-column"}
          onClick={() => {
            const value = prompt("Column name");
            if (value) {
              taskBoard.current.instance.columns.add({
                id: value,
                text: value,
              });
            }
          }}
        >
          Add column
        </button>
      </nav>
      <BryntumTaskBoard
        ref={taskBoard}
        project={project}
        {...taskBoardConfig}
      />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Add the following styles to App.css to style the header similar to Trello:

/* src/App.css */
@import '~@bryntum/taskboard/taskboard.material.css';

* {
  margin: 0px;
  box-sizing: border-box;
}

.header {
  display: flex;
  padding: 20px;
  justify-content: space-between;
  align-items: center;
  color: white;
  background-color: dodgerblue;
}

.header .heading {
  font-size: 24px;
}

.header .add-column {
  padding: 5px 10px;
  border-radius: 5px;
  border: none;
  font-size: 16px;
  cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

TaskBoard with header

You can add the onChange event listener on the BryntumProjectModel to update the tasks state when the project data changes. The onChange handler will receive an object describing the change, and you can use the change.action to check if a new task is added or an existing one is updated:

// src/App.js
import React, { useRef, useState } from "react";
import {
  BryntumTaskBoard,
  BryntumProjectModel,
} from "@bryntum/taskboard-react";
import { taskBoardConfig } from "./AppConfig";
import { projectData } from "./AppData";
import "./App.css";

function App() {
  const taskBoard = useRef();
  const project = useRef();
  const [tasks, setTasks] = useState(projectData.tasks);
  const [assignments] = useState(projectData.assignments);
  const [resources] = useState(projectData.users);
  function onChange(change) {
    if(change.action === 'add') {
      setTasks(() => [...tasks, change.records[0].data])
    }
    if(change.action === 'update') {
      const updatedTask =  change.record.data
      const newTasks = [...tasks].filter(item => item.id !== updatedTask.id)
      setTasks(() => [...newTasks, updatedTask])
    }
  }

  return (
    <>
      <BryntumProjectModel
        ref={project}
        tasks={tasks}
        assignments={assignments}
        resources={resources}
        onChange={onChange}
      />
      <nav className={"header"}>
        <h1 className={"heading"}>Trello using Bryntum TaskBoard</h1>
        <button
          className={"add-column"}
          onClick={() => {
            const value = prompt("Column name");
            if (value) {
              taskBoard.current.instance.columns.add({
                id: value,
                text: value,
              });
            }
          }}
        >
          Add column
        </button>
      </nav>
      <BryntumTaskBoard
        ref={taskBoard}
        project={project}
        {...taskBoardConfig}
      />
    </>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

And that's it! You've successfully created a Trello-like project management application using Bryntum TaskBoard. This application provides features such as using drag and drop for tasks and dynamically adding columns out-of-the-box:

TaskBoard in action

Additional Functionality

Your basic Trello clone is ready, but with Bryntum, you can add even more functionality to improve the user experience with just a few props.

For instance, to enable moving columns using drag-and-drop functionality, you just need to pass the columnDragFeature prop to the BryntumTaskBoard to enable it. Now users can quickly move the columns around in the order they want:

     // other code above
     <BryntumTaskBoard
        ref={taskBoard}
        project={project}
        columnDragFeature
        {...taskBoardConfig}
      />
     // example below
Enter fullscreen mode Exit fullscreen mode

TaskBoard column drag and drop

Another helpful feature is the TaskTooltip, which shows task details when hovering over a task. You can enable this by passing the taskTooltipFeature prop to BryntumTaskBoard:

    // other code above
    <BryntumTaskBoard
        ref={taskBoard}
        project={project}
        columnDragFeature
        taskTooltipFeature
        {...taskBoardConfig}
    />
    // example below
Enter fullscreen mode Exit fullscreen mode

Task details tooltip

Conclusion

After completing this tutorial, you now have a Trello-like project management application that was created using the Bryntum TaskBoard. If you want to keep going, you can improve this application by utilizing other features from the TaskBoard documentation.

Bryntum is a software company that creates beautiful and performant web components for professional usage, including TaskBoard, Scheduler, and Gantt. Bryntum's web components come with thorough documentation, making them easy to integrate with popular frontend frameworks, including React and Vue.js.

Bryntum helps the world stay on schedule. Our component library offers a selection of high-quality, advanced UI controls for various frontend frameworks. Want to learn more? Try our scheduling and Gantt components at bryntum.com.

Top comments (0)