DEV Community

Manoj Swami
Manoj Swami

Posted on

Creating a Modern React App: Vite + TypeScript + ESLint + Tailwind + shadcn/ui and Zustand

In this guide, we'll walk through the process of setting up a React application with the latest features and popular libraries. We'll be using React 19, React Router, Tailwind CSS, shadcn/ui, ESLint with Prettier, and Zustand for state management. By the end of this tutorial, you'll have a fully configured project ready for development.

Setting Up the Project

Let's start by creating a new React project using Vite, which provides a faster and leaner development experience.

npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
Enter fullscreen mode Exit fullscreen mode

This command creates a new React project with TypeScript support. Now, let's install the necessary dependencies:

npm install react@19 react-dom@19 react-router-dom@6 zustand@4 @types/react@19 @types/react-dom@19
npm install -D tailwindcss postcss autoprefixer eslint prettier eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser
Enter fullscreen mode Exit fullscreen mode

Configuring Tailwind CSS

To set up Tailwind CSS, run the following command:

npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

This creates a tailwind.config.js file. Update it with the following content:

module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Now, add the Tailwind directives to your src/index.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Setting Up ESLint and Prettier

Create .eslintrc.js and .prettierrc files in the root of your project:

touch .eslintrc.js .prettierrc
Enter fullscreen mode Exit fullscreen mode

Add the following content to .eslintrc.js:

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: ['react', '@typescript-eslint'],
  rules: {
    'react/react-in-jsx-scope': 'off',
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

And to .prettierrc:

{
  "semi": true,
  "tabWidth": 2,
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "all",
  "jsxSingleQuote": true,
  "bracketSpacing": true
}
Enter fullscreen mode Exit fullscreen mode

Installing and Configuring shadcn/ui

To use shadcn/ui, we need to set it up in our project:

npx shadcn-ui@latest init
Enter fullscreen mode Exit fullscreen mode

Follow the prompts to configure shadcn/ui for your project. This will set up the necessary files and configurations.

Setting Up Zustand

Create a new file src/store.ts for our Zustand store:

import create from 'zustand';

interface AppState {
  count: number;
  increment: () => void;
  decrement: () => void;
}

export const useAppStore = create<AppState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));
Enter fullscreen mode Exit fullscreen mode

Updating package.json Scripts

Add the following scripts to your package.json:

"scripts": {
  "dev": "vite",
  "build": "tsc && vite build",
  "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
  "preview": "vite preview",
  "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
  "lint:fix": "eslint src --ext ts,tsx --fix"
}
Enter fullscreen mode Exit fullscreen mode

Creating a Sample App

Let's create a simple app to demonstrate the usage of our setup. Update src/App.tsx:

import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { Button } from './components/ui/button';
import { useAppStore } from './store';

function Home() {
  const { count, increment, decrement } = useAppStore();

  return (
    <div className='p-4'>
      <h1 className='text-2xl font-bold mb-4'>Home</h1>
      <p className='mb-4'>Count: {count}</p>
      <Button onClick={increment} className='mr-2'>Increment</Button>
      <Button onClick={decrement}>Decrement</Button>
    </div>
  );
}

function About() {
  return <div className='p-4'>
    <h1 className='text-2xl font-bold'>About</h1>
  </div>;
}

function App() {
  return (
    <Router>
      <div className='p-4'>
        <nav className='mb-4'>
          <Link to='/' className='mr-4'>Home</Link>
          <Link to='/about'>About</Link>
        </nav>
        <Routes>
          <Route path='/' element={<Home />} />
          <Route path='/about' element={<About />} />
        </Routes>
      </div>
    </Router>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Running the Application

Now you can run your application using the following command:

npm run dev
Enter fullscreen mode Exit fullscreen mode

This will start the development server, and you can view your app at http://localhost:5173.

Conclusion

You now have a modern React application set up with React 19, React Router, Tailwind CSS, shadcn/ui, ESLint with Prettier, and Zustand. This setup provides a solid foundation for building scalable and maintainable React applications.

Happy coding!

Top comments (2)

Collapse
 
perisicnikola37 profile image
Nikola Perišić

I've launched a beginner friendly project for frontend devs with same tech stack. If you'd like to stay updated on its progress, be sure to give it a star on GitHub! 🌟
Repository
Libs: Ts particles, Framer motion, React maps, React Icons, Swiper etc.
Live link
Image description

Collapse
 
joanny_bernardeau_ac67521 profile image
Joanny Bernardeau

Hello, I made an API for copy/paste. On the start of a project. But it's not perfect and your article makes me see nuances. start-projet
Thank