Fetch live weather data for any city and display temperature, conditions, and an icon. This project practices asynchronous JavaScript and working with third-party APIs.

Requirements

Features

  • Search by city name
  • Display temperature (°C), humidity, wind speed, and weather description
  • Show a weather icon from the API
  • Handle loading, empty, and error states

Step 1: Get an API Key

  1. Sign up at openweathermap.org
  2. Navigate to API keys and generate a key
  3. New keys may take up to two hours to activate

Store your key in a variable — never commit it to a public repository.

Step 2: Project Structure

  weather-app/
├── index.html
├── style.css
└── app.js
  

index.html

  <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Weather App</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="app">
    <h1>Weather</h1>
    <form id="search-form">
      <input id="city-input" type="text" placeholder="Enter city..." required>
      <button type="submit">Search</button>
    </form>
    <div id="status" class="hidden"></div>
    <div id="weather" class="hidden">
      <img id="icon" alt="Weather icon">
      <h2 id="city-name"></h2>
      <p id="description"></p>
      <p id="temperature"></p>
      <p id="details"></p>
    </div>
  </div>
  <script src="app.js"></script>
</body>
</html>
  

Step 3: Fetch Weather Data

  const API_KEY = 'YOUR_API_KEY_HERE';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

async function fetchWeather(city) {
  const url = `${BASE_URL}?q=${encodeURIComponent(city)}&units=metric&appid=${API_KEY}`;
  const response = await fetch(url);

  if (!response.ok) {
    if (response.status === 404) throw new Error('City not found');
    throw new Error('Failed to fetch weather data');
  }
  return response.json();
}
  

Step 4: Render Results

  function displayWeather(data) {
  document.getElementById('city-name').textContent =
    `${data.name}, ${data.sys.country}`;
  document.getElementById('description').textContent =
    data.weather[0].description;
  document.getElementById('temperature').textContent =
    `${Math.round(data.main.temp)}°C`;
  document.getElementById('details').textContent =
    `Humidity: ${data.main.humidity}% · Wind: ${data.wind.speed} m/s`;
  document.getElementById('icon').src =
    `https://openweathermap.org/img/wn/${data.weather[0].icon}@2x.png`;
}
  

Step 5: UI State Management

  const statusEl = document.getElementById('status');
const weatherEl = document.getElementById('weather');

function showLoading() {
  statusEl.textContent = 'Loading...';
  statusEl.classList.remove('hidden');
  weatherEl.classList.add('hidden');
}

function showError(message) {
  statusEl.textContent = message;
  statusEl.classList.remove('hidden');
  weatherEl.classList.add('hidden');
}

function showWeather(data) {
  statusEl.classList.add('hidden');
  weatherEl.classList.remove('hidden');
  displayWeather(data);
}
  

Step 6: Search Handler

  document.getElementById('search-form').addEventListener('submit', async e => {
  e.preventDefault();
  const city = document.getElementById('city-input').value.trim();
  if (!city) return;

  showLoading();
  try {
    const data = await fetchWeather(city);
    showWeather(data);
    localStorage.setItem('lastCity', city);
  } catch (err) {
    showError(err.message);
  }
});

// Load last searched city on page load
const lastCity = localStorage.getItem('lastCity');
if (lastCity) {
  showLoading();
  fetchWeather(lastCity).then(showWeather).catch(showError);
}
  

Step 7: Basic Styling

  .app { max-width: 400px; margin: 2rem auto; text-align: center; font-family: system-ui, sans-serif; }
#search-form { display: flex; gap: 0.5rem; margin: 1rem 0; }
#search-form input { flex: 1; padding: 0.5rem; }
.hidden { display: none; }
#weather img { width: 100px; }
#temperature { font-size: 3rem; font-weight: bold; }
  

Extension Ideas

  • 5-day forecast — use the /forecast endpoint
  • Geolocation — detect the user’s city with navigator.geolocation
  • Unit toggle — switch between °C and °F
  • Recent searches — store and display the last five cities
  • Dynamic backgrounds — change page color based on weather condition (sunny, rainy, cloudy)