React+TailwindCSS template

Author : JaNakh Pon , August 09, 2021

Tags

Intro

We are going to set up TailwindCSS in create-react-app with TypeScript and build a simple responsive todo template with pagination🔥.


Step 1 (Installation)

Let's get started by generating a react app using create-react-app:

 > npx create-react-app tailwindreacttodo --template typescript
 > cd tailwindreacttodo 

Now we have a react app with typescript, so let's install dependencies for TailwindCSS:

 > npm install -D tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

And now let's install craco(Create React App Configuration Override):

 > npm install @craco/craco

Now, it's time to make some changes in package.json because we want to use craco instead of react-scripts,

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject"
  },

Next, create a craco.config.js at the root of our project and add the tailwindcss and autoprefixer as PostCSS plugins:

// craco.config.js
module.exports = {
  style: {
    postcss: {
      plugins: [
        require('tailwindcss'),
        require('autoprefixer'),
      ],
    },
  },
}

Next, generate your tailwind.config.js file:

 > npx tailwindcss-cli@latest init

and configure the purge[] for Tailwind to remove unused styles in production,

// tailwind.config.js
module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

And now, let's include tailwind to our main css file(index.css):

/* ./src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Step 2 (Design Thinking)

Now, if we think about a simple single page todo app interface, we can imagine it in three parts:

  1. Interactive Form
  2. List of tasks/ Container of tasks
  3. Pagination

Since using TailwindCSS is unlike using components based UI libraries(bootstrap, material-ui, semantic-ui, ...etc) and more like writing vanilla CSS: we are going to use grid and flex even though it's just a simple single page todo ui.


Step 3 (Implementation)

For more informations about css class read tailwind documentation here. First, let's create a main container to wrap the three components. we want to use a simple container and set margin left right to auto but we want to keep a certain distance for margin top and bottom:

const App = () => {
  return (
    <div className="container mx-auto lg:my-32 md:my-30 sm:my-15 ">
      {/* 3 components go here */}
    </div>
  );
}
export default App;
Interactive form/ Interactive Component

For Interactive form/component we might need:

  • Input field for creating/saving new task/todo
  • Input field for searching task/todo
  • select boxes for sorting by properties in ascending or descending order

So, we might want to use display:flex for that:

const InteractiveComponent = () => {
    return (
        <>
            <div className="flex justify-center m-5">
                <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl flex flex-col items-center">
                    <form className="flex justify-between w-full">
                        <input type="text" placeholder={`write things down here ...`} />
                    </form>
                </section>
            </div>
            <div className="flex justify-center m-5">
                <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl flex flex-col items-center">
                    <form className="flex justify-between w-full">
                        <div className=" w-full relative text-gray-700">
                            <input className="w-full h-10 pl-8 pr-3" type="text" placeholder="search here .." />
                            <div className="absolute inset-y-0 left-0 flex items-center px-2 pointer-events-none">
                                <svg className="w-4 h-4 fill-current" viewBox="0 0 20 20">
                                    <path d="M18.125,15.804l-4.038-4.037c0.675-1.079,1.012-2.308,1.01-3.534C15.089,4.62,12.199,1.75,8.584,1.75C4.815,1.75,1.982,4.726,2,8.286c0.021,3.577,2.908,6.549,6.578,6.549c1.241,0,2.417-0.347,3.44-0.985l4.032,4.026c0.167,0.166,0.43,0.166,0.596,0l1.479-1.478C18.292,16.234,18.292,15.968,18.125,15.804 M8.578,13.99c-3.198,0-5.716-2.593-5.733-5.71c-0.017-3.084,2.438-5.686,5.74-5.686c3.197,0,5.625,2.493,5.64,5.624C14.242,11.548,11.621,13.99,8.578,13.99 M16.349,16.981l-3.637-3.635c0.131-0.11,0.721-0.695,0.876-0.884l3.642,3.639L16.349,16.981z"></path>
                                </svg>
                            </div>
                        </div>
                        <select>
                            <option className="p-1">updated_at</option>
                            <option className="p-1">created_at</option>
                            <option className="p-1">id</option>
                            <option className="p-1">title</option>
                        </select>
                        <select>
                            <option className="p-1">ASC</option>
                            <option className="p-1">DESC</option>
                        </select>
                    </form>
                </section>
            </div>
        </>
    )
}
export default InteractiveComponent;
List of tasks

For displaying list of tasks, might want to use a combination for grid and flex, Grid will be using as a wrapping container and Flex will be used in each Item of the list. Btw, my combination is not a good looking one!😂:

const TasksComponent = () => {
    return (
        <>
            <div className="grid grid-flow-row auto-rows-max lg:mt-5 sm:mt-2">
                <div className="flex justify-center mx-8">
                    <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl">
                        <p className="text-sm font-medium">Found 4 tasks!</p>
                    </section>
                </div>

                <div className="flex justify-center mt-10 mx-8">
                    <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl">
                        <h2 className="font-bold ml-2">Lorem Ipsum, <span className="font-light text-sm">2 days ago</span></h2>
                        <input type="checkbox" />
                        <span className="text-left text-sm leading-3 tracking-wider px-1">
                            Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups
                            |&nbsp;<span className="cursor-pointer hover:uppercase hover:font-bolder hover:text-red-500" > remove?</span></span>
                    </section>
                </div>


                <div className="flex justify-center mt-10 mx-8">
                    <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl">
                        <h2 className="font-bold ml-2">Lorem Ipsum, <span className="font-light text-sm">2 days ago</span></h2>
                        <input type="checkbox" />
                        <span className="text-left text-sm leading-3 tracking-wider px-1">
                            Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups
                            |&nbsp;<span className="cursor-pointer hover:uppercase hover:font-bolder hover:text-red-500" > remove?</span></span>
                    </section>
                </div>


                <div className="flex justify-center mt-10 mx-8">
                    <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl">
                        <h2 className="font-bold ml-2">Lorem Ipsum, <span className="font-light text-sm">2 days ago</span></h2>
                        <input type="checkbox" />
                        <span className="text-left text-sm leading-3 tracking-wider px-1">
                            Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups
                            |&nbsp;<span className="cursor-pointer hover:uppercase hover:font-bolder hover:text-red-500" > remove?</span></span>
                    </section>
                </div>

                <div className="flex justify-center mt-10 mx-8">
                    <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl">
                        <h2 className="font-bold ml-2">Lorem Ipsum, <span className="font-light text-sm">2 days ago</span></h2>
                        <input type="checkbox" />
                        <span className="text-left text-sm leading-3 tracking-wider px-1">
                            Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups
                            |&nbsp;<span className="cursor-pointer hover:uppercase hover:font-bolder hover:text-red-500" > remove?</span></span>
                    </section>
                </div>


            </div>
        </>
    )
}
export default TasksComponent;
Pagination

For Pagination, we want to have buttons in a row and make them look good in center?.. we might also want to use flex for positioning items in a row

const PaginationComponent = () => {
    return (
        <>
            <div className="flex justify-center mt-10 mx-8">
                <section className="w-10/12  sm:w-10/11 lg:w-1/2 max-w-2xl flex justify-center">
                    <nav aria-label="Page navigation">
                        <ul className="inline-flex space-x-2">
                            <li>
                                <button className={`w-10 h-10 text-white transition-colors duration-150 bg-gray-500 border border-r-0 border-gray-500 rounded-full focus:shadow-outline`} >1</button>
                            </li>
                            <li>
                                <button className={`w-10 h-10 transition-colors duration-150 rounded-full focus:shadow-outline hover:bg-gray-100`} >2</button>
                            </li>
                            <li>
                                <button className={`w-10 h-10 transition-colors duration-150 rounded-full focus:shadow-outline hover:bg-gray-100`}>3</button>
                            </li>
                        </ul>
                    </nav>
                </section>
            </div>
        </>
    )
}
export default PaginationComponent;

Not very much of an explaination right? 😹 Don't worry 😉, get the source code down below and use it as an example and build a new one out of it while referencing TailwindCSS amazing doc!!!.

Source Code.

Go Back.