Examples
An earlier release
These pages document @evanion/react-widget 0.2.0. npm install @evanion/react-widget gives you 0.3.3, documented here. Values on this page were produced by running 0.2.0 in CI at d50a1c6 and are not re-executed.
Real-world examples showing how to use the React Widget System effectively.
Live Demo: E-commerce Showcase
Copy the code below into your React project to see this e-commerce showcase in action:
Basic Blog Sidebar
A simple sidebar with news and user information.
import { createWidgets } from '@evanion/react-widget';
// Define widget components
const NewsTeaser = ({ title, publishedAt, body }) => (
<article className="news-teaser">
<h3>{title}</h3>
<time>{publishedAt.toLocaleDateString()}</time>
<p>{body}</p>
</article>
);
const UserSidebar = ({ username, avatar, messages }) => (
<div className="user-info">
<img src={avatar} alt={username} />
<span>{username}</span>
<span>{messages} messages</span>
</div>
);
// Create widget system
const { Widgets } = createWidgets({
components: {
news: NewsTeaser,
userInfo: UserSidebar,
},
});
// Define layout data
const sidebarItems = [
{
id: 'userinfo',
type: 'userInfo',
props: {
username: 'Evanion',
avatar: 'https://evanion.com/avatar.jpg',
messages: 5,
},
},
{
id: 'news1',
type: 'news',
props: {
title: 'Breaking News',
publishedAt: new Date('2024-01-15'),
body: 'This is a sample news article...',
},
},
];
function BlogSidebar() {
return <Widgets items={sidebarItems} />;
}E-commerce Product Showcase
Product showcase with custom chrome (wrappers).
import { createWidgets } from '@evanion/react-widget';
// Widget components
const ProductCard = ({ name, price, image }) => (
<div className="product-card">
<img src={image} alt={name} />
<h4>{name}</h4>
<p>${price}</p>
</div>
);
const Banner = ({ image, title, cta }) => (
<div className="banner">
<img src={image} alt={title} />
<h2>{title}</h2>
<button>{cta}</button>
</div>
);
// Create widget system with custom chrome
const { Widgets } = createWidgets({
components: {
productCard: ProductCard,
banner: Banner,
},
chrome: {
wrapper: ({ children }) => (
<div className="product-showcase">
<header>Featured Products</header>
<div className="products-grid">{children}</div>
</div>
),
},
});
// Product showcase data
const showcaseItems = [
{
id: 'banner1',
type: 'banner',
props: {
image: '/banner.jpg',
title: 'Summer Sale',
cta: 'Shop Now',
},
},
{
id: 'product1',
type: 'productCard',
props: {
name: 'Wireless Headphones',
price: 99.99,
image: '/headphones.jpg',
},
},
];
function ProductShowcase() {
return <Widgets items={showcaseItems} />;
}Dashboard with Statistics
Admin dashboard with stat cards and action buttons.
import { createWidgets } from '@evanion/react-widget';
// Widget components
const StatCard = ({ title, value, trend }) => (
<div className="stat-card">
<h4>{title}</h4>
<div className="value">{value}</div>
<div className="trend">{trend}</div>
</div>
);
const ActionButton = ({ label, action, variant }) => (
<button className={`btn btn-${variant}`} data-action={action}>
{label}
</button>
);
// Create dashboard widget system
const { Widgets } = createWidgets({
components: {
statCard: StatCard,
actionButton: ActionButton,
},
chrome: {
wrapper: ({ children }) => <div className="dashboard-grid">{children}</div>,
},
});
// Dashboard data
const dashboardItems = [
{
id: 'stats1',
type: 'statCard',
props: {
title: 'Total Users',
value: '1,234',
trend: '+12%',
},
},
{
id: 'stats2',
type: 'statCard',
props: {
title: 'Revenue',
value: '$45,678',
trend: '+8%',
},
},
{
id: 'action1',
type: 'actionButton',
props: {
label: 'Export Data',
action: 'export',
variant: 'primary',
},
},
];
function AdminDashboard() {
return <Widgets items={dashboardItems} />;
}Nested Widgets
Card widget with nested content using the Output component.
import { createWidgets } from '@evanion/react-widget';
// Widget components
const CardWidget = ({ title, Output }) => (
<div className="card">
<h3>{title}</h3>
<Output />
</div>
);
const TextWidget = ({ content }) => <p>{content}</p>;
const ImageWidget = ({ src, alt }) => <img src={src} alt={alt} />;
// Create widget system
const { Widgets } = createWidgets({
components: {
card: CardWidget,
text: TextWidget,
image: ImageWidget,
},
});
// Nested widget data
const nestedItems = [
{
id: 'card1',
type: 'card',
props: {
title: 'My Card',
},
children: [
{
id: 'text1',
type: 'text',
props: { content: 'Nested text content' },
},
{
id: 'image1',
type: 'image',
props: {
src: '/image.jpg',
alt: 'Nested image',
},
},
],
},
];
function NestedWidgets() {
return <Widgets items={nestedItems} />;
}Instance-Specific Overrides
Different components for different contexts.
import { createWidgets } from '@evanion/react-widget';
// Default news component
const NewsTeaser = ({ title, publishedAt, body }) => (
<article className="news-teaser">
<h3>{title}</h3>
<time>{publishedAt.toLocaleDateString()}</time>
<p>{body}</p>
</article>
);
// Create base widget system
const { Widgets } = createWidgets({
components: {
news: NewsTeaser,
},
});
// Special news component for homepage
const FeaturedNews = ({ title, publishedAt, body }) => (
<div className="featured-news">
<h2>Featured: {title}</h2>
<p>Special styling for this news item</p>
</div>
);
// News data
const newsItems = [
{
id: 'news1',
type: 'news',
props: {
title: 'Regular News',
publishedAt: new Date(),
body: 'Regular content',
},
},
];
// Use different components for different pages
function HomePage() {
return <Widgets items={newsItems} components={{ news: FeaturedNews }} />;
}
function BlogPage() {
return <Widgets items={newsItems} />; // Uses default NewsTeaser
}Error Handling
The system gracefully handles errors and unknown widget types.
import { createWidgets } from '@evanion/react-widget';
const ValidWidget = ({ content }) => <div>Valid: {content}</div>;
const { Widgets } = createWidgets({
components: {
valid: ValidWidget,
},
});
// Mixed valid and invalid widgets
const mixedItems = [
{
id: 'unknown1',
type: 'unknown-widget', // This will be skipped with a warning
props: { content: 'This should not render' },
},
{
id: 'valid1',
type: 'valid',
props: { content: 'This will render' },
},
];
function ErrorHandlingExample() {
return <Widgets items={mixedItems} />;
// Only the valid widget will render
// Unknown widget will be skipped with console warning
}Last updated on