Code A Program
React Weather App Tutorial Build a Beautiful UI with Tailwind CSS
Published on August 17, 2025

React Weather App Tutorial Build a Beautiful UI with Tailwind CSS

Building a Beautiful Weather App with React and Tailwind CSS

Weather apps are one of the most popular beginner projects in frontend development. They’re practical, fun, and make excellent portfolio pieces! In this blog, I’ll walk you through building a modern weather app using React for UI logic and state management, and Tailwind CSS for styling.

What Does This Weather App Do?

  • Allows users to search for any city.

  • Fetches current weather data from OpenWeatherMap.

  • Dynamically displays the weather type, temperature, and city/country info.

  • Shows a relevant weather icon based on the conditions.

Technology Stack

  • React: Efficient user interface and state management

  • Tailwind CSS: Utility-first styling, making layout and design simple and responsive

  • OpenWeatherMap API: Real-time weather data for any location

Youtube Video:

How the Code Works: Step-by-step

JavaScript
import { useRef, useState } from "react";

const Api_key = "";

const App = () => {
  const inputRef = useRef(null);
  const [apiData, setApiData] = useState(null);
  const [showWeather, setShowWeather] = useState(null);

  const [loading, setLoading] = useState(false);

  const WeatherTypes = [
    {
      type: "Clear",
      img: "https://cdn-icons-png.flaticon.com/512/6974/6974833.png",
    },
    {
      type: "Rain",
      img: "https://cdn-icons-png.flaticon.com/512/3351/3351979.png",
    },
    {
      type: "Snow",
      img: "https://cdn-icons-png.flaticon.com/512/642/642102.png",
    },
    {
      type: "Clouds",
      img: "https://cdn-icons-png.flaticon.com/512/414/414825.png",
    },
    {
      type: "Haze",
      img: "https://cdn-icons-png.flaticon.com/512/1197/1197102.png",
    },
    {
      type: "Smoke",
      img: "https://cdn-icons-png.flaticon.com/512/4380/4380458.png",
    },
    {
      type: "Mist",
      img: "https://cdn-icons-png.flaticon.com/512/4005/4005901.png",
    },
    {
      type: "Drizzle",
      img: "https://cdn-icons-png.flaticon.com/512/3076/3076129.png",
    },
  ];

  const fetchWeather = async () => {
    const URL = `https://api.openweathermap.org/data/2.5/weather?q=${inputRef.current.value}&units=metric&appid=${Api_key}`;
    setLoading(true);
    fetch(URL)
      .then((res) => res.json())
      .then((data) => {
        setApiData(null);
        if (data.cod == 404 || data.cod == 400) {
          // ARRAY OF OBJ
          setShowWeather([
            {
              type: "Not Found",
              img: "https://cdn-icons-png.flaticon.com/512/4275/4275497.png",
            },
          ]);
        }
        setShowWeather(
          WeatherTypes.filter(
            (weather) => weather.type === data.weather[0].main
          )
        );
        console.log(data);
        setApiData(data);
        setLoading(false);
      })
      .catch((err) => {
        console.log(err);
        setLoading(false);
      });
  };

  return (
    <div className="bg-gray-800 h-screen grid place-items-center">
      <div className="bg-white w-96 p-4 rounded-md">
        <div className="flex items-center justify-between">
          <input
            type="text"
            ref={inputRef}
            placeholder="Enter Your Location"
            className="text-xl border-b
          p-1 border-gray-200 font-semibold uppercase flex-1"
          />
          <button onClick={fetchWeather}>
            <img
              src="https://cdn-icons-png.flaticon.com/512/758/758651.png"
              alt="..."
              className="w-8"
            />
          </button>
        </div>
        <div
          className={`duration-300 delay-75  overflow-hidden
         ${showWeather ? "h-[27rem]" : "h-0"}`}
        >
          {loading ? (
            <div className="grid place-items-center h-full">
              <img
                src="https://cdn-icons-png.flaticon.com/512/1477/1477009.png"
                alt="..."
                className="w-14 mx-auto mb-2 animate-spin"
              />
            </div>
          ) : (
            showWeather && (
              <div className="text-center flex flex-col gap-6 mt-10">
                {apiData && (
                  <p className="text-xl font-semibold">
                    {apiData?.name + "," + apiData?.sys?.country}
                  </p>
                )}
                <img
                  src={showWeather[0]?.img}
                  alt="..."
                  className="w-52 mx-auto"
                />
                <h3 className="text-2xl font-bold text-zinc-800">
                  {showWeather[0]?.type}
                </h3>

                {apiData && (
                  <>
                    <div className="flex justify-center">
                      <img
                        src="https://cdn-icons-png.flaticon.com/512/7794/7794499.png"
                        alt="..."
                        className="h-9 mt-1"
                      />
                      <h2 className="text-4xl font-extrabold">
                        {apiData?.main?.temp}&#176;C
                      </h2>
                    </div>
                  </>
                )}
              </div>
            )
          )}
        </div>
      </div>
    </div>
  );
};

export default App;

State & Hooks Used

  • useRef: To directly get the city input value.

  • useState: Three states to track API data, selected weather type, and loading status.

Weather Type Array

A lookup table matches OpenWeatherMap’s main weather types to stylish icons.

Fetching Weather Data

The main function, fetchWeather, constructs a request URL using the city the user entered, then fetches the JSON weather data:

  • If the city doesn't exist, it shows the "Not Found" icon.

  • Otherwise, it finds the matching weather type and sets the display state.

UI Rendering Logic

  • The root container is styled using Tailwind for centering and spacing.

  • Input is styled and paired with a search icon as a button.

  • The weather card expands smoothly when results are available.

  • Weather info (city, country, temperature) and the relevant icon/title display dynamically.

  • Loading state is managed to show a spinner while the fetch completes.

Error Handling

If the API returns an error (like city not found), an appropriate message and icon are displayed to the user.


Full Example Code

You can find the full code above—just make sure to add your OpenWeatherMap API key!


How to Customize and Extend

  • Add More Details: Show humidity, wind speed, description, etc.

  • Support Multiple Units: °C/°F toggle.

  • Add Forecasts: Expand to show hourly/daily forecasts.

  • Improve Error Messaging: Handle blank or invalid inputs gracefully.

  • Use Environment Variables: For the API key, never hardcode secrets!

Final Thoughts

This project helps you practice working with APIs, managing state with React hooks, and building beautiful, reactive interfaces with Tailwind CSS. Plus, it’s easy to extend—with so many ways to enhance the features or visual design.

Whether you’re a React newcomer or looking to polish your skills, building a weather app is a great way to learn practical frontend concepts while making something genuinely useful.

Try building your own version, add your favorite features, and showcase your skills!

Thanks for reading!!!

Share:
Download Source Code

Get the complete source code for this tutorial. Includes all files, components, and documentation to help you follow along.

View on GitHub

📦What's Included:

  • • Complete source code files
  • • All assets and resources used
  • • README with setup instructions
  • • Package.json with dependencies
💡Free to use for personal and commercial projects