Skip to main content

Overview

The Weather Finder app uses two main display components that work together to show comprehensive weather information:
  • CurrentWeather: Displays current conditions for a city
  • WeatherForecast: Shows a 7-day forecast with daily highs and lows
Both components are designed with accessibility in mind and use emoji icons for visual weather representation.

CurrentWeather Component

Purpose

Displays the current weather conditions for a searched city, including temperature, weather description, and wind speed. Location: weather-finder/src/components/CurrentWeather.tsx

Props

data
WeatherData
required
Weather data object containing city information and current conditions
interface WeatherData {
  cityName: string;
  country: string;
  current: CurrentWeatherData;
  daily: DailyForecastData;
}

WeatherData Interface

interface CurrentWeatherData {
  temperature_2m: number;      // Temperature in Celsius
  wind_speed_10m: number;      // Wind speed in km/h
  weather_code: number;        // WMO weather code
}

interface WeatherData {
  cityName: string;            // City name from geocoding
  country: string;             // Country code
  current: CurrentWeatherData; // Current weather details
  daily: DailyForecastData;    // Forecast data
}

Features

  • City Display: Shows city name and country
  • Weather Emoji: Visual representation using getWeatherInfo() utility
  • Temperature: Rounded to nearest degree Celsius
  • Weather Description: Human-readable condition (e.g., “Soleado”, “Nublado”)
  • Wind Speed: Displayed in km/h
  • ARIA Labels: Accessible with aria-label attributes

Usage Example

import { CurrentWeather } from './components/CurrentWeather';
import type { WeatherData } from './types/weather';

function WeatherApp() {
  const weatherData: WeatherData = {
    cityName: 'Madrid',
    country: 'ES',
    current: {
      temperature_2m: 24.5,
      wind_speed_10m: 12.3,
      weather_code: 0
    },
    daily: { /* ... */ }
  };

  return <CurrentWeather data={weatherData} />;
}

Implementation

import type { WeatherData } from '../types/weather';
import { getWeatherInfo } from '../utils/weatherCodes';

interface Props {
  data: WeatherData;
}

export function CurrentWeather({ data }: Props) {
  const { cityName, country, current } = data;
  const { description, emoji } = getWeatherInfo(current.weather_code);

  return (
    <section className="current-weather" aria-label="Clima actual">
      <div className="city-info">
        <h2 className="city-name">{cityName}</h2>
        <span className="city-country">{country}</span>
      </div>

      <div className="weather-main">
        <span className="weather-emoji" role="img" aria-label={description}>
          {emoji}
        </span>
        <div className="temperature-block">
          <span className="temperature">{Math.round(current.temperature_2m)}°C</span>
          <span className="weather-description">{description}</span>
        </div>
      </div>

      <div className="weather-details">
        <div className="detail-item">
          <span className="detail-icon" aria-hidden="true">💨</span>
          <span className="detail-label">Viento</span>
          <span className="detail-value">{current.wind_speed_10m} km/h</span>
        </div>
      </div>
    </section>
  );
}

WeatherForecast Component

Purpose

Displays a 7-day weather forecast with daily temperature ranges and weather conditions. Location: weather-finder/src/components/WeatherForecast.tsx

Props

daily
DailyForecastData
required
Forecast data containing arrays of daily weather information
interface DailyForecastData {
  time: string[];              // ISO date strings
  temperature_2m_max: number[]; // Daily max temps
  temperature_2m_min: number[]; // Daily min temps
  weather_code: number[];       // WMO weather codes
}

DailyForecastData Interface

interface DailyForecastData {
  time: string[];              // Array of dates: ["2026-03-04", "2026-03-05", ...]
  temperature_2m_max: number[]; // Max temperatures: [25.5, 26.2, ...]
  temperature_2m_min: number[]; // Min temperatures: [15.3, 16.1, ...]
  weather_code: number[];       // Weather codes: [0, 2, 3, ...]
}

Features

  • 7-Day Forecast: Displays all days from the forecast data
  • Today Highlight: First card marked with special styling
  • Date Formatting: Uses Spanish locale for day/date display
  • Weather Emojis: Visual representation for each day
  • Temperature Range: Shows both max and min temperatures
  • Accessibility: Comprehensive ARIA labels for each forecast card

Usage Example

import { WeatherForecast } from './components/WeatherForecast';
import type { DailyForecastData } from './types/weather';

function WeatherApp() {
  const forecastData: DailyForecastData = {
    time: ['2026-03-04', '2026-03-05', '2026-03-06'],
    temperature_2m_max: [25.5, 26.2, 24.8],
    temperature_2m_min: [15.3, 16.1, 14.9],
    weather_code: [0, 2, 3]
  };

  return <WeatherForecast daily={forecastData} />;
}

Implementation

import type { DailyForecastData } from '../types/weather';
import { getWeatherInfo } from '../utils/weatherCodes';

interface Props {
  daily: DailyForecastData;
}

function formatDay(dateStr: string): string {
  const date = new Date(`${dateStr}T12:00:00`);
  return date.toLocaleDateString('es-ES', {
    weekday: 'short',
    day: 'numeric',
    month: 'short',
  });
}

export function WeatherForecast({ daily }: Props) {
  return (
    <section className="forecast" aria-label="Pronóstico de 7 días">
      <h3 className="forecast-title">Pronóstico de 7 días</h3>
      <div className="forecast-list">
        {daily.time.map((date, i) => {
          const { description, emoji } = getWeatherInfo(daily.weather_code[i]);
          const isToday = i === 0;
          return (
            <div
              key={date}
              className={`forecast-card${isToday ? ' forecast-card--today' : ''}`}
              aria-label={`${isToday ? 'Hoy' : formatDay(date)}: ${description}, máx ${Math.round(daily.temperature_2m_max[i])}°, mín ${Math.round(daily.temperature_2m_min[i])}°`}
            >
              <span className="forecast-day">{isToday ? 'Hoy' : formatDay(date)}</span>
              <span className="forecast-emoji" role="img" aria-hidden="true">
                {emoji}
              </span>
              <span className="forecast-desc">{description}</span>
              <div className="forecast-temps">
                <span className="temp-max">{Math.round(daily.temperature_2m_max[i])}°</span>
                <span className="temp-separator">/</span>
                <span className="temp-min">{Math.round(daily.temperature_2m_min[i])}°</span>
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
}

Weather Utility: getWeatherInfo

Both components use the getWeatherInfo utility to convert WMO weather codes to emoji and descriptions:
// Example usage
import { getWeatherInfo } from '../utils/weatherCodes';

const { description, emoji } = getWeatherInfo(0);
// Result: { description: "Despejado", emoji: "☀️" }

Common Weather Codes

CodeDescriptionEmoji
0Despejado (Clear)☀️
1-3Parcialmente nublado🌤️
45-48Niebla (Fog)🌫️
51-57Llovizna (Drizzle)🌦️
61-67Lluvia (Rain)🌧️
71-77Nieve (Snow)❄️
80-82Chubascos (Showers)🌦️
95-99Tormenta (Thunderstorm)⛈️

Styling Guidelines

.current-weather {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  padding: 2rem;
  border-radius: 12px;
  color: white;
}

.weather-emoji {
  font-size: 5rem;
}

.temperature {
  font-size: 3rem;
  font-weight: bold;
}

.weather-details {
  display: flex;
  gap: 1rem;
  margin-top: 1.5rem;
}

Accessibility Features

Both components use <section> tags with aria-label attributes to define landmark regions for screen readers.
  • Current weather has aria-label="Clima actual"
  • Forecast has aria-label="Pronóstico de 7 días"
  • Each forecast card has a descriptive aria-label with full weather information
  • Emojis use role="img" for semantic meaning
  • aria-label provides text alternative for weather emoji
  • Decorative emojis use aria-hidden="true"
A screen reader would announce: “Pronóstico de 7 días, región. Hoy: Despejado, máx 25°, mín 15°“

Complete Example

import { CurrentWeather } from './components/CurrentWeather';
import { WeatherForecast } from './components/WeatherForecast';
import { SearchBar } from './components/SearchBar';
import { LoadingSpinner } from './components/LoadingSpinner';
import { ErrorMessage } from './components/ErrorMessage';
import { useWeather } from './hooks/useWeather';

export function WeatherPage() {
  const { weatherData, status, error, searchCity } = useWeather();

  return (
    <div className="weather-page">
      <SearchBar 
        onSearch={searchCity}
        isLoading={status === 'loading'}
      />

      {status === 'loading' && <LoadingSpinner />}
      
      {status === 'error' && <ErrorMessage message={error} />}
      
      {status === 'success' && weatherData && (
        <>
          <CurrentWeather data={weatherData} />
          <WeatherForecast daily={weatherData.daily} />
        </>
      )}
    </div>
  );
}

SearchBar

Search component for city input

LoadingSpinner

Loading state indicator

ErrorMessage

Error display component

Best Practices

Always round temperatures for better UX: Math.round(temp)
Use proper ARIA labels for accessibility
Provide visual and text descriptions for weather conditions
Highlight “today” in forecasts for better orientation
Use semantic HTML (<section>, proper heading hierarchy)
Display units (°C, km/h) clearly next to values

Build docs developers (and LLMs) love