DEV Community

Cover image for How to Setup Up a Next.js App with Tailwind CSS and TypeScript
Niraj Narkhede
Niraj Narkhede

Posted on

How to Setup Up a Next.js App with Tailwind CSS and TypeScript

Introduction

Hey there, fellow UI developer! Are you ready to embark on an exciting journey to create a powerful and stylish web application? You've come to the right place! In this blog post, we're going to walk through the process of setting up a Next.js app with Tailwind CSS and TypeScript. This combination of technologies will give you a robust foundation for building modern, responsive, and type-safe web applications.

Whether you're new to these tools or looking to refresh your knowledge, this guide will provide you with all the information you need to get started. We'll cover everything from installation to configuration, and even throw in some tips and tricks along the way. So, grab your favorite beverage, fire up your code editor, and let's dive in!

Why Next.js, Tailwind CSS, and TypeScript?

Before we start coding, let's take a moment to understand why this tech stack is so popular among developers:

Next.js: The React Framework for Production

Next.js is a powerful React framework that provides a ton of built-in features to make your development process smoother. Some key benefits include:

  • Server-side rendering
  • Automatic code splitting
  • Route pre-fetching
  • Built-in CSS support
  • API routes

Tailwind CSS: Utility-First CSS Framework

Tailwind CSS is a highly customizable, low-level CSS framework that gives you all the building blocks you need to create bespoke designs. Here's why developers love it:

  • Rapid UI development
  • Consistent design system
  • Highly customizable
  • Smaller bundle sizes with PurgeCSS

TypeScript: JavaScript with Superpowers

TypeScript adds static typing to JavaScript, which can help catch errors early and improve code quality. Benefits include:

  • Better code documentation
  • Enhanced IDE support
  • Easier refactoring
  • Improved team collaboration

Now that we understand the why, let's get into the how!

Setting Up Your Development Environment

Before we create our next-app with Tailwind and TypeScript, we need to make sure our development environment is properly set up.

Node.js and npm

First things first, you'll need Node.js installed on your machine. Next.js requires Node.js 12.0 or later. To check if you have Node.js installed, open your terminal and run:

node --version
Enter fullscreen mode Exit fullscreen mode

If you don't have Node.js installed, or if your version is outdated, head over to the official Node.js website and download the latest stable version.

Code Editor

While you can use any text editor for coding, I highly recommend using Visual Studio Code. It's free, open-source, and has excellent support for JavaScript, TypeScript, and React development. Plus, there are numerous helpful extensions available that can boost your productivity.

Creating Your Next.js App

Now that we have our environment ready, let's create our Next.js app with Tailwind CSS and TypeScript.

Using create-next-app

The easiest way to get started with Next.js is by using create-next-app. This CLI tool sets up a new Next.js project with a single command. Open your terminal, navigate to the directory where you want to create your project, and run:

npx create-next-app@latest my-next-app --typescript --tailwind --eslint
Enter fullscreen mode Exit fullscreen mode

Let's break down this command:

  • npx allows us to run the latest version of create-next-app without installing it globally
  • my-next-app is the name of your project (feel free to change this!)
  • --typescript flag adds TypeScript support
  • --tailwind flag adds Tailwind CSS configuration
  • --eslint flag adds ESLint for code linting

After running this command, create-next-app will set up a new Next.js project with TypeScript and Tailwind CSS pre-configured. It might take a few minutes to install all the necessary dependencies.

Project Structure

Once the installation is complete, let's take a look at the project structure:

my-next-app/
├── node_modules/
├── pages/
│   ├── _app.tsx
│   ├── index.tsx
│   └── api/
├── public/
├── styles/
│   └── globals.css
├── .eslintrc.json
├── next-env.d.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.js
└── tsconfig.json
Enter fullscreen mode Exit fullscreen mode

Let's go through some of the key files and directories:

pages/

This directory contains your application's routes. Each file in this directory becomes a route based on its name.

pages/_app.tsx

This is the main component that wraps all other pages. It's used to keep state when navigating between pages or to add global styles.

pages/index.tsx

This is your home page. It's what users will see when they visit the root of your site.

styles/globals.css

This file contains global styles and is where Tailwind's base styles are imported.

tailwind.config.js

This is where you can customize your Tailwind installation.

tsconfig.json

This file specifies the root files and the compiler options required to compile the project.

Customizing Your Next.js App

Now that we have our basic setup, let's customize it a bit to get a feel for how everything works together.

Modifying the Home Page

Open pages/index.tsx and replace its contents with the following:

import Head from 'next/head'

export default function Home() {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">
      <Head>
        <title>My Next.js App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="flex flex-col items-center justify-center flex-1 px-20 text-center">
        <h1 className="text-6xl font-bold">
          Welcome to{' '}
          <a className="text-blue-600" href="https://nextjs.org">
            Next.js!
          </a>
        </h1>

        <p className="mt-3 text-2xl">
          Get started by editing{' '}
          <code className="p-3 font-mono text-lg bg-gray-100 rounded-md">
            pages/index.tsx
          </code>
        </p>

        <div className="flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full">
          <a
            href="https://nextjs.org/docs"
            className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
          >
            <h3 className="text-2xl font-bold">Documentation &rarr;</h3>
            <p className="mt-4 text-xl">
              Find in-depth information about Next.js features and API.
            </p>
          </a>

          <a
            href="https://nextjs.org/learn"
            className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
          >
            <h3 className="text-2xl font-bold">Learn &rarr;</h3>
            <p className="mt-4 text-xl">
              Learn about Next.js in an interactive course with quizzes!
            </p>
          </a>
        </div>
      </main>

      <footer className="flex items-center justify-center w-full h-24 border-t">
        <a
          className="flex items-center justify-center"
          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{' '}
          <img src="/vercel.svg" alt="Vercel Logo" className="h-4 ml-2" />
        </a>
      </footer>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

This code creates a simple landing page using Tailwind CSS classes for styling. It includes a main heading, a brief description, and two card-like links to Next.js resources.

Adding a New Page

Let's add a new page to our app. Create a new file called about.tsx in the pages directory and add the following content:

import Head from 'next/head'
import Link from 'next/link'

export default function About() {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">
      <Head>
        <title>About - My Next.js App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="flex flex-col items-center justify-center flex-1 px-20 text-center">
        <h1 className="text-6xl font-bold">About Page</h1>
        <p className="mt-3 text-2xl">
          This is a simple about page to demonstrate routing in Next.js
        </p>
        <Link href="/">
          <a className="mt-6 text-blue-600 hover:underline">Back to Home</a>
        </Link>
      </main>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

This creates a simple "About" page and demonstrates how easy it is to add new pages in Next.js.

Working with TypeScript

One of the great things about using TypeScript with Next.js is the improved developer experience. Let's create a simple component to see TypeScript in action.

Create a new directory called components in the root of your project, and inside it, create a file called Button.tsx:

import React from 'react'

interface ButtonProps {
  text: string
  onClick: () => void
}

const Button: React.FC<ButtonProps> = ({ text, onClick }) => {
  return (
    <button
      className="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700"
      onClick={onClick}
    >
      {text}
    </button>
  )
}

export default Button
Enter fullscreen mode Exit fullscreen mode

Now, let's use this button in our index.tsx file. Update the file to include:

import Head from 'next/head'
import Button from '../components/Button'

export default function Home() {
  const handleClick = () => {
    alert('Button clicked!')
  }

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">
      {/* ... (previous content) ... */}
      <Button text="Click me!" onClick={handleClick} />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

With TypeScript, you'll get autocompletion and type checking for your component props, making it easier to use components correctly and catch errors early.

Customizing Tailwind CSS

Tailwind CSS is highly customizable. Let's make a few changes to the default configuration to see how it works.

Open tailwind.config.js and update it to look like this:

module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      colors: {
        'custom-blue': '#1e40af',
        'custom-green': '#15803d',
      },
      fontFamily: {
        sans: ['Roboto', 'sans-serif'],
      },
    },
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

This configuration adds two custom colors and changes the default font to Roboto.

To use the new custom colors, you can update the Button component:

const Button: React.FC<ButtonProps> = ({ text, onClick }) => {
  return (
    <button
      className="px-4 py-2 font-bold text-white bg-custom-blue rounded hover:bg-custom-green"
      onClick={onClick}
    >
      {text}
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

Remember to import the Roboto font in your _app.tsx file:

import '../styles/globals.css'
import { AppProps } from 'next/app'
import Head from 'next/head'

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <link
          href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
          rel="stylesheet"
        />
      </Head>
      <Component {...pageProps} />
    </>
  )
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

Adding Interactivity with React Hooks

Let's add some interactivity to our app using React hooks. We'll create a simple counter component.

Create a new file components/Counter.tsx:

import React, { useState } from 'react'
import Button from './Button'

const Counter: React.FC = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  return (
    <div className="flex flex-col items-center mt-8">
      <h2 className="text-2xl font-bold mb-4">Counter: {count}</h2>
      <div className="flex space-x-4">
        <Button text="Increment" onClick={increment} />
        <Button text="Decrement" onClick={decrement} />
      </div>
    </div>
  )
}

export default Counter
Enter fullscreen mode Exit fullscreen mode

Now, add this Counter component to your index.tsx:

import Head from 'next/head'
import Button from '../components/Button'
import Counter from '../components/Counter'

export default function Home() {
  const handleClick = () => {
    alert('Button clicked!')
  }

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">
      {/* ... (previous content) ... */}
      <Button text="Click me!" onClick={handleClick} />
      <Counter />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

This demonstrates how we can use React hooks (useState in this case) with TypeScript in our Next.js app.

Fetching Data

Next.js provides several methods for fetching data. Let's create a simple example using the getStaticProps function to fetch data at build time.

Create a new file pages/users.tsx:

import { GetStaticProps } from 'next'
import Head from 'next/head'
import Link from 'next/link'

interface User {
  id: number
  name: string
  email: string
}

interface UsersProps {
  users: User[]
}

export default function Users({ users }: UsersProps) {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2">
      <Head>
        <title>Users - My Next.js App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="flex flex-col items-center justify-center flex-1 px-20 text-center">
        <h1 className="text-6xl font-bold mb-8">Users</h1>
        <ul className="space-y-4">
          {users.map((user) => (
            <li key={user.id} className="bg-gray-100 p-4 rounded-md">
              <h2 className="text-xl font-bold">{user.name}</h2>
              <p>{user.email}</p>
            </li>
          ))}
        </ul>
        <Link href="/">
          <a className="mt-8 text-blue-600 hover:underline">Back to Home</a>
        </Link>
      </main>
    </div>
  )
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/users')
  const users: User[] = await res.json()

  return {
    props: {
      users,
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

This example fetches a list of users from a JSON placeholder API and displays them on a new page.

Wrapping Up

Congratulations! You've successfully set up a Next.js app with Tailwind CSS and TypeScript.

Happy Coding !!

Top comments (0)