I recently added a clean little weather widget to my Flarum forum's header and wanted to share how you can do the same! It displays your local weather icon and current temperature, matches your site’s theme colors, and is responsive (hidden on mobile).
🎨 Step 1: Get Your Weather Icons
There’s a great free set of weather icons available here:
👉 Open Weather SVG Icons by isneezy
✅ Download these and upload them to your server.
For example:
https://yourdomain.com/weather/images/01d.svg
https://yourdomain.com/weather/images/02n.svg
... and so on.
These filenames match the codes from the OpenWeatherMap API (more on that below).
🔑 Step 2: Sign Up for a Free OpenWeatherMap API Key
- Go to https://openweathermap.org/api
- Create a free account and generate your API key.
- Copy your API key — you’ll use this in your script.
🌎 Step 3: Find Your City ID
OpenWeather uses City IDs for accuracy (especially when cities share names).
To find your City ID:
Example:
Marietta, GA has City ID: 4207783
🗂️ Step 4: Prepare Your Files
You'll need two files hosted on your site:
weather-widget.js (your JavaScript logic)
weather-widget.css (your styling)
🟢 Sample weather-widget.js:
if (!window.weatherWidgetLoaded) {
window.weatherWidgetLoaded = true;
document.addEventListener('DOMContentLoaded', function() {
const apiKey = 'YOUR_OPENWEATHER_API_KEY'; // Replace with your OpenWeather API key
const cityId = 'YOUR_CITY_ID'; // Replace with your city's ID (example: Marietta, GA = 4207783)
const iconPath = 'https://yourdomain.com/weather/images/'; // Folder where your weather icons and placeholder.svg are stored
const placeholderIcon = `${iconPath}placeholder.svg`;
const apiURL = `https://api.openweathermap.org/data/2.5/weather?id=${cityId}&units=imperial&appid=${apiKey}`;
fetch(apiURL)
.then(response => {
if (!response.ok) throw new Error('Weather API error');
return response.json();
})
.then(data => {
const iconCode = data.weather[0].icon;
const iconUrl = `${iconPath}${iconCode}.svg`;
const temperature = Math.round(data.main.temp);
const widget = document.getElementById('weather-icon-widget');
widget.innerHTML = `
<div class="weather-nav-widget">
<img class="weather-icon" src="${placeholderIcon}" alt="Loading Weather Icon">
<span>${temperature}°</span>
</div>
`;
const preloadIcon = new Image();
preloadIcon.src = iconUrl;
preloadIcon.alt = "Weather Icon";
preloadIcon.onload = () => {
const imgElement = widget.querySelector('.weather-icon');
if (imgElement) {
imgElement.src = iconUrl;
}
};
const searchContainer = document.querySelector('.Search');
if (searchContainer) {
searchContainer.style.display = 'flex';
searchContainer.style.alignItems = 'center';
searchContainer.appendChild(widget);
}
})
.catch(error => {
console.error('Weather Widget Error:', error);
});
});
}
🎨 Sample weather-widget.css:
.weather-nav-widget {
display: flex;
align-items: center;
gap: 8px;
font-size: 20px;
color: var(--primary-color);
font-weight: 600;
line-height: 1;
margin-left: 12px;
}
.weather-nav-widget img {
width: 34px;
height: 34px;
display: block;
background-color: var(--button-bg);
border-radius: 50%;
padding: 1px;
box-sizing: border-box;
}
@media (max-width: 1100px) {
#weather-icon-widget {
display: none !important;
}
}
🔧 Step 5: Add This to Your Flarum Custom Header:
<div id="weather-icon-widget" style="display: flex; align-items: center; margin-left: 10px;"></div>
<link rel="stylesheet" href="https://yourdomain.com/weather/weather-widget.css">
<script src="https://yourdomain.com/weather/weather-widget.js"></script>
✅ Result:
- Fully responsive (hides on mobile).
- Matches your site theme colors.
- Clean SVG icon + temperature, injected right into your nav bar.
💡 Bonus Tips:
- You can easily adjust the breakpoint where it hides (change
1100px to whatever fits your theme).
- Tooltip text (
title="Current Weather") can be customized to say your city, like “Marietta Current Weather.”
Update
- Added a placeholder SVG as suggested by @Subarist . Please create the below svg file.
Title: placeholder.svg
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="20" stroke="rgba(0, 0, 0, 0.3)" stroke-width="5" fill="none"/>
<circle cx="25" cy="25" r="20" stroke="var(--primary-color)" stroke-width="5" fill="none"
stroke-linecap="round" stroke-dasharray="90,150"
transform="rotate(-90 25 25)">
<animateTransform attributeName="transform" type="rotate"
from="0 25 25" to="360 25 25" dur="1s" repeatCount="indefinite"/>
</circle>
</svg>
If you use this on your forum, I’d love to see how it turns out! 🎉
Examples:
Light Mode

Dark Mode
