Introduction
Build widgets
SDK
Useful links
Search
/
Smart widget previewer
A React component for previewing and interacting with Nostr Smart Widgets kind:30033. This package allows you to easily display smart widgets in your React applications with full interaction support.
Installation
npm install smart-widget-previewer
or
yarn add smart-widget-previewer
Overview
Smart Widget Previewer renders Nostr Smart Widgets kind:30033 in your React applications, supporting all widget features:
- Basic widgets with images, inputs, and multiple buttons
- Action/Tool widgets with specialized behavior
- Interactive buttons for various purposes (redirect, nostr, zap, post, app)
- Dynamic content updates when interacting with post-type buttons
Basic Example
import React from 'react';
import { Widget } from 'smart-widget-previewer';
function WidgetPreview() {
// Example Nostr smart widget event
const widgetEvent = {
id: "widget_event_id",
pubkey: "widget_creator_pubkey",
created_at: 1681234567,
kind: 30033,
tags: [
["d", "unique-identifier"],
["l", "basic"],
["image", "https://example.com/widget-image.jpg"],
["input", "Search for something..."],
["button", "Visit Website", "redirect", "https://example.com"],
["button", "Zap Creator", "zap", "creator@lightning.address"]
],
sig: "widget_signature"
};
// Handle button interactions
const handleNostrButton = (url) => {
console.log('Nostr button clicked with URL:', url);
// Process nostr URL or identifier
return url; // Return processed URL if needed
};
const handleZapButton = (address) => {
console.log('Zap button clicked with address:', address);
// Process lightning address or invoice
return address; // Return processed address if needed
};
return (
<div className="widget-container">
<h2>Smart Widget Preview</h2>
<Widget
event={widgetEvent}
onNostrButton={handleNostrButton}
onZapButton={handleZapButton}
width={400}
widthUnit="px"
/>
</div>
);
}
export default WidgetPreview;
Widget Component Props
The Widget component accepts the following props:
| Prop | Type | Description |
|---|---|---|
event | Object | Required - Nostr event object for the smart widget |
onNextWidget | Function | Callback for when a new widget is returned after interaction |
onZapButton | Function | Callback for handling zap button clicks, receives lightning address |
onNostrButton | Function | Callback for handling nostr button clicks, receives nostr URL |
onActionWidget | Function | Callback for handling action/tool widget clicks |
width | Number | Width of the widget (defaults to 100% if not specified) |
widthUnit | String | Unit for width: "px", "em", "rem", or "%" (defaults to "%") |
buttonStyleClassName | String | Custom CSS class(es) for widget buttons |
inputStyleClassName | String | Custom CSS class(es) for widget input field |
widgetBackgroundColor | String | Custom background color (hex or RGB) |
widgetBorderColor | String | Custom border color (hex or RGB) |
widgetBorderRaduis | String | Custom border radius in pixels |
userHexPubkey | String | Current user's public key in hex format |
errorMessage | String | Custom error message for invalid widgets |
Widget Types and Behavior
Basic Widgets
Basic widgets can include:
- Image (required)
- Input field (optional)
- Up to 6 buttons with different actions
// Example of a basic widget event
const basicWidget = {
id: "widget_event_id",
pubkey: "widget_creator_pubkey",
created_at: 1681234567,
kind: 30033,
tags: [
["d", "unique-identifier"],
["l", "basic"],
["image", "https://example.com/widget-image.jpg"],
["input", "Enter your search..."],
["button", "Visit Website", "redirect", "https://example.com"],
["button", "View Profile", "nostr", "nostr:npub1..."],
["button", "Send Zap", "zap", "user@lightning.address"]
],
sig: "widget_signature"
};
Action/Tool Widgets
Action/Tool widgets are designed for single actions:
- Image (required)
- Icon (required but included in tags)
- Exactly 1 button (if including input, the button must be of type 'app')
- Clicking anywhere on the widget triggers the button action
// Example of an action widget event
const actionWidget = {
id: "widget_event_id",
pubkey: "widget_creator_pubkey",
created_at: 1681234567,
kind: 30033,
tags: [
["d", "unique-identifier"],
["l", "action"],
["image", "https://example.com/widget-image.jpg"],
["icon", "https://example.com/widget-icon.png"],
["button", "Take Action", "app", "https://app.example.com/action"]
],
sig: "widget_signature"
};
Button Types
The widget supports different types of buttons:
| Type | Description | Behavior |
|---|---|---|
redirect | Standard link | Opens URL in new tab |
nostr | Nostr action | Calls onNostrButton with the URL |
zap | Lightning payment | Calls onZapButton with the address |
post | Form submission | Submits input data and can update the widget |
app | App integration | Calls onActionWidget with the URL |
Handling Widget Interactions
Post Button Interaction
When a user interacts with a "post" type button, the widget will:
- Submit the input value along with widget information to the specified URL
- Process the response, which should be a new widget event
- Update the displayed widget with the new content
- Call
onNextWidgetwith the new widget event
// Example handling the next widget update
function handleNextWidget(newWidgetEvent) {
console.log('New widget received:', newWidgetEvent);
// You can store this widget in state or handle it as needed
return newWidgetEvent;
}
<Widget
event={widgetEvent}
onNextWidget={handleNextWidget}
userHexPubkey="user_pubkey_for_authentication"
/>
Action/Tool Widget Interaction
When a user clicks on an action/tool widget, the onActionWidget callback is called:
function handleActionWidget(url) {
console.log('Action widget clicked with URL:', url);
// Handle the action, such as opening a mini app or modal
}
<Widget
event={actionWidgetEvent}
onActionWidget={handleActionWidget}
/>
Styling Widgets
You can customize the appearance of widgets using the provided props:
<Widget
event={widgetEvent}
buttonStyleClassName="my-custom-button-class"
inputStyleClassName="my-custom-input-class"
widgetBackgroundColor="#f5f5f5"
widgetBorderColor="#e0e0e0"
widgetBorderRaduis="15"
width={350}
widthUnit="px"
/>
Complete Example
import React, { useState } from 'react';
import { Widget } from 'smart-widget-previewer';
function WidgetContainer() {
const [currentWidget, setCurrentWidget] = useState({
id: "widget_event_id",
pubkey: "widget_creator_pubkey",
created_at: 1681234567,
kind: 30033,
tags: [
["d", "unique-identifier"],
["l", "basic"],
["image", "https://example.com/widget-image.jpg"],
["input", "Search for content..."],
["button", "Search", "post", "https://api.example.com/search"],
["button", "View Creator", "nostr", "nostr:npub1..."],
["button", "Support", "zap", "creator@lightning.address"]
],
sig: "widget_signature"
});
// Handle when a post button returns a new widget
const handleNextWidget = (newWidget) => {
setCurrentWidget(newWidget);
return newWidget;
};
// Handle nostr button clicks
const handleNostrButton = (url) => {
console.log('Processing nostr URL:', url);
// Here you would integrate with your Nostr client
// Example: openNostrProfile(url);
return url;
};
// Handle zap button clicks
const handleZapButton = (address) => {
console.log('Processing lightning address:', address);
// Here you would integrate with your Lightning wallet
// Example: openZapModal(address);
return address;
};
// Handle action widget clicks
const handleActionWidget = (url) => {
console.log('Opening action at URL:', url);
// Here you would handle the action
// Example: openActionInFrame(url);
};
return (
<div className="widget-demo">
<h1>Smart Widget Demo</h1>
<div className="widget-wrapper">
<Widget
event={currentWidget}
onNextWidget={handleNextWidget}
onNostrButton={handleNostrButton}
onZapButton={handleZapButton}
onActionWidget={handleActionWidget}
width={450}
widthUnit="px"
widgetBackgroundColor="#ffffff"
widgetBorderColor="#dddddd"
widgetBorderRaduis="12"
userHexPubkey="user_hex_pubkey_here"
errorMessage="Widget could not be displayed"
/>
</div>
</div>
);
}
export default WidgetContainer;
Browser Compatibility
Smart Widget Previewer is compatible with all modern browsers that support React.