Build interactive widgets with real API data
Select an API that provides interesting data (weather, news, images, etc.)
Create HTML structure and CSS styling for your widget
Use fetch() to get data and handle loading/error states
Enable user controls, refresh buttons, and customization options
class SimpleWidget {
constructor(containerId, apiUrl) {
this.container = document.getElementById(containerId);
this.apiUrl = apiUrl;
this.init();
}
async init() {
this.render();
await this.loadData();
}
render() {
this.container.innerHTML = `
<div class="widget">
<h3>My Widget</h3>
<div id="data">Loading...</div>
<button onclick="this.refresh()">Refresh</button>
</div>
`;
}
async loadData() {
try {
const response = await fetch(this.apiUrl);
const data = await response.json();
this.displayData(data);
} catch (error) {
this.showError(error.message);
}
}
}
class AdvancedWidget extends SimpleWidget {
constructor(containerId, config) {
super(containerId, config.apiUrl);
this.config = config;
this.cache = new Map();
this.autoRefresh = config.autoRefresh || false;
}
// Caching mechanism
async loadData(useCache = true) {
const cacheKey = this.getCacheKey();
if (useCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < 300000) { // 5 min cache
this.displayData(cached.data);
return;
}
}
// Fetch new data
const data = await this.fetchData();
this.cache.set(cacheKey, {
data: data,
timestamp: Date.now()
});
this.displayData(data);
}
// Auto-refresh functionality
enableAutoRefresh(interval = 30000) {
this.refreshInterval = setInterval(() => {
this.loadData(false);
}, interval);
}
}
/* Widget Container */
.widget {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.widget:hover {
transform: translateY(-2px);
}
/* Loading States */
.loading {
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
color: #666;
}
.loading::before {
content: '';
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 10px;
}
/* Responsive Grid */
.widget-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}