URL: https://www.progressiverobot.com/react-beautiful-uis-ant-design/

Ant Design is a React UI library that has a plethora of easy-to-use components that are useful for building elegant user interfaces.

Created by Chinese conglomerate Alibaba, Ant Design is used by several big names: Alibaba (of course), Tencent, Baidu, and more. While Material-UI remains the most popular React UI library with over 40k stars on Github, Ant Design is currently at a close second, and is quickly closing-in the gap.

There's also a mobile version of Ant Design, and you can learn more about it here.

Getting Started

ant illustration for: Getting Started

In this tutorial, we'll build a basic todo application to showcase a few of Ant Design's components. Our first step will be to set up our boilerplate. I've done so using create-react-app.

Then we'll need to add the antd dependency to the project:

				
					
$ yarn add antd



# or, using npm:

$ npm install antd --save

				
			

Before we start building our <Todo /> component, we'll add a reference to it in the root component:

				
					
[label index.js]

import React from "react";

import ReactDOM from "react-dom";

import Todo from "./todo";



import "./styles.css";



function App() {

  return (

    &lt;div className="App"&gt;

      &lt;Todo /&gt;

    &lt;/div&gt;

  );

}



const rootElement = document.getElementById("root");

ReactDOM.render(&lt;App /&gt;, rootElement);

				
			

Building the Todo Component

Now we can start building our <Todo /> component. Open a new file called todo.js with the following contents:

				
					
[label todo.js]

import React from "react";



export default class Todo extends React.Component {

  render() {

    return (

      &lt;div className="todoContainer"&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;

      &lt;/div&gt;

    );

  }

}

				
			

I'm going to edit the stylesheet so that the .todoContainer is nicely centered on the page.

				
					
[label styles.css]

.App {

  font-family: sans-serif;

  text-align: center;

}



.todoContainer {

  width: 75%;

  margin-left: auto;

  margin-right: auto;

}

				
			

Cool! Now let's add an input to the <Todo /> component. We'll use the one provided by antd, making sure to also import the CSS file for the library.

				
					
[label todo.js]

import React from "react";

import { Input } from "antd";



// Don't forget to include the CSS styles for antd!

import "antd/dist/antd.css";



export default class Todo extends React.Component {

  render() {

    return (

      &lt;div className="todoContainer" /&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;



        &lt;Input

          placeholder="What needs to be done?"

        /&gt;

      &lt;/div&gt;

    );

  }

}

				
			

Great, now we are rendering a text input box. However, it doesn't do anything. We need our input to add its content to the component's state so we can render a list of todos. We'll use the onPressEnter prop on our <Input /> to detect when the user submits a new todo:

				
					
[label todo.js]

// --- snip ---



export default class Todo extends React.Component {

  constructor() {

    super();



    // Initialize the state

    this.state = {

      todos: []

    };

  }



  handlePressEnter = e =&gt; {

    // Create a todo object containing its index and content

    const todo = {

      index: this.state.todos.length,

      content: e.target.value

    };



    // Add the todo to our array

    const newTodos = this.state.todos.concat(todo);



    this.setState({

      todos: newTodos

    });



    // Clear input

    e.target.value = "";

  };



  render() {

    return (

      &lt;div className="todoContainer"&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;



        &lt;Input

          placeholder="What needs to be done?"

          onPressEnter={this.handlePressEnter}

        /&gt;

      &lt;/div&gt;

    );

  }

}

				
			

Now handlePressEnter() will update the component's state whenever the user inputs a new todo item, but we still have to render them.

For this purpose we can use Ant Design's <List /> component. It takes in an array as its dataSource prop and renders it according to whatever function is passed to its renderItem prop.

				
					
[label todo.js]

import React from "react";

import { Input, List } from "antd";



import "antd/dist/antd.css";



export default class Todo extends React.Component {

  // --- snip ---



  render() {

    return (

      &lt;div className="todoContainer"&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;



        &lt;Input

          placeholder="What needs to be done?"

          onPressEnter={this.handlePressEnter}

        /&gt;



        &lt;List

          {/* emptyText sets the text to display in an empty list */}

          locale={{ emptyText: "No todo items" }}

          dataSource={this.state.todos}

          renderItem={item =&gt; (

            &lt;List.Item&gt;{item.content}&lt;/List.Item&gt;

          )}

        /&gt;

      &lt;/div&gt;

    );

  }

}

				
			

Ta-da! Now we have our basic todo app working! However, there's still more that we can do to make it better!

Getting Fancy

Our todo application is up and running. However, there is more that we need to add: most importantly, a remove button. We'll also add a date picker, because why not?

To avoid making our <Todo /> overly complicated, I'm going to extract the <List.Item /> into its own separate component. I will also define a new method, removeTodo() to remove todo items given its index. I'll then pass that method into our new component.

To serve as a remove button, we can use Ant's <Icon /> component. Add it to the <List.Item />'s action prop, which takes an array of components. To see the full list of icons, see this page on the Ant Design website.

				
					
[label todo.js]

import React from "react";

import { Input, List, Icon } from "antd";



import "antd/dist/antd.css";



export default class Todo extends React.Component {

  // --- snip ---



  removeTodo = index =&gt; {

    let newTodos = [...this.state.todos];



    // Remove element

    newTodos.splice(index, 1);



    // Decrement greater indexes

    for (let i = index; i &lt; newTodos.length; i++) {

      newTodos[i].index -= 1;

    }



    // Update state

    this.setState({

      todos: newTodos

    });

  };



  render() {

    return (

      &lt;div className="todoContainer"&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;



        &lt;Input

          placeholder="What needs to be done?"

          onPressEnter={this.handlePressEnter}

        /&gt;



        &lt;List

          locale={{ emptyText: "No todo items" }}

          dataSource={this.state.todos}

          renderItem={item =&gt; (

            &lt;TodoItem

              todo={item}

              removeTodo={this.removeTodo}

            /&gt;

          )}

        /&gt;

      &lt;/div&gt;

    );

  }

}



class TodoItem extends React.Component {

  remove = () =&gt; {

    // Remove this TodoItem

    this.props.removeTodo(this.props.todo.index);

  };



  render() {

    return (

      &lt;List.Item

        actions={[

          &lt;Icon

            type="close-circle"

            theme="filled"

            onClick={this.remove}

          /&gt;

        ]}

      &gt;

        {this.props.todo.content}

      &lt;/List.Item&gt;

    );

  }

}

				
			

Great! Now all that's left is to add Ant's <DatePicker /> component. To do so, we're going to update the handlePressEnter() method by adding date and dateString properties to the todo objects we're storing in our state. Then we'll need an additional method, setDate(), to update those properties.

				
					
[label todo.js]

import React from "react";

import { Input, List, Icon, DatePicker } from "antd";



import "antd/dist/antd.css";



export default class Todo extends React.Component {

  // --- snip ---



  handlePressEnter = e =&gt; {

    // Create a todo object containing its index, content,

    // as well as an empty date

    const todo = {

      index: this.state.todos.length,

      content: e.target.value,

      date: null,

      dateString: ""

    };



    // Add the new todo to our array

    const newTodos = this.state.todos.concat(todo);



    this.setState({

      todos: newTodos

    });



    // Clear input

    e.target.value = "";

  };



  setDate = (index, date, dateString) =&gt; {

    // Set the date of the given todo

    let newTodos = [...this.state.todos];

    newTodos[index].date = date;

    newTodos[index].dateString = dateString;



    // Initialize the state

    this.setState({

      todos: newTodos

    });

  };



  render() {

    return (

      &lt;div className="todoContainer"&gt;

        &lt;h1&gt;TODO App&lt;/h1&gt;



        &lt;Input

          placeholder="What needs to be done?"

          onPressEnter={this.handlePressEnter}

        /&gt;



        &lt;List

          locale={{ emptyText: "No todo items" }}

          dataSource={this.state.todos}

          renderItem={item =&gt; (

            &lt;TodoItem

              todo={item}

              removeTodo={this.removeTodo}

              setDate={this.setDate}

            /&gt;

          )}

        /&gt;

      &lt;/div&gt;

    );

  }

}



class TodoItem extends React.Component {

  remove = () =&gt; {

    // Remove this TodoItem

    this.props.removeTodo(this.props.todo.index);

  };



  handleDateChange = (date, dateString) =&gt; {

    // Update the date when changed

    this.props.setDate(this.props.todo.index, date, dateString);

  }



  render() {

    return (

      &lt;List.Item

        actions={[

          &lt;DatePicker

            format="MM/DD/YYYY"

            onChange={this.handleDateChange}

            value={this.props.todo.date}

          /&gt;,

          &lt;Icon

            type="close-circle"

            theme="filled"

            onClick={this.remove}

          /&gt;

        ]}

      &gt;

        {this.props.todo.content}

      &lt;/List.Item&gt;

    );

  }

}

				
			

And voilà! 🎉

We now have our fully functional todo app utilizing Ant Design! If you'd like to learn more about Ant, check out their docs.

You can find the full code for this post on CodeSandbox.