Skip to content

Widget System

The Widget System allows you to create custom, interactive React components that can be dynamically rendered in peer conversations. Widgets enable rich data visualization, interactive forms, and dynamic content that goes beyond simple text responses.

Overview

Widgets provide:

  • Interactive Visualizations: Charts, graphs, and data displays
  • Dynamic Content: Real-time data presentation
  • Custom UI Components: Tailored user experiences
  • Reusable Components: Share widgets across peers
  • Secure Execution: Sandboxed JavaScript/React environment

Key Concepts

What is a Widget?

A widget is a self-contained React component defined through JSON configuration and JavaScript code. When a peer sends a message with widget data, Cognipeer AI dynamically renders the widget with the provided data.

Widget Structure

javascript
{
  "key": "sales-funnel-progress",
  "name": "Sales Funnel Progress",
  "description": "Displays sales pipeline stages with conversion rates",
  "category": "sales",
  "tags": ["sales", "analytics", "funnel"],
  "schema": { /* JSON Schema for data validation */ },
  "component": "/* React component code */"
}

Widget Components

  1. Key: Unique identifier (e.g., sales-funnel-progress)
  2. Name: Display name for the widget
  3. Description: What the widget does
  4. Schema: JSON Schema defining expected data structure
  5. Component: React component code (JavaScript)
  6. Category: Organization category
  7. Tags: Searchable keywords

Creating a Widget

Step 1: Navigate to Widget Management

  1. Go to SettingsWidgets
  2. Click "Create New Widget"

Step 2: Define Basic Information

javascript
{
  "key": "task-kanban",
  "name": "Task Kanban Board",
  "description": "Kanban-style task board with drag-and-drop",
  "category": "productivity",
  "tags": ["tasks", "kanban", "project-management"]
}

Step 3: Define Data Schema

Specify the expected data structure using JSON Schema:

json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "columns": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "tasks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "title": { "type": "string" },
                "priority": { "type": "string" },
                "assignee": { "type": "string" }
              },
              "required": ["id", "title"]
            }
          }
        },
        "required": ["id", "title", "tasks"]
      }
    }
  },
  "required": ["columns"]
}

Step 4: Write Component Code

Create a React component (JavaScript):

javascript
function TaskKanbanWidget({ data }) {
  const { columns } = data;
  
  return (
    <div className="kanban-board">
      {columns.map(column => (
        <div key={column.id} className="kanban-column">
          <h3>{column.title}</h3>
          <div className="task-list">
            {column.tasks.map(task => (
              <div key={task.id} className="task-card">
                <h4>{task.title}</h4>
                {task.priority && (
                  <span className={`priority-${task.priority}`}>
                    {task.priority}
                  </span>
                )}
                {task.assignee && (
                  <div className="assignee">{task.assignee}</div>
                )}
              </div>
            ))}
          </div>
        </div>
      ))}
      
      <style jsx>{`
        .kanban-board {
          display: flex;
          gap: 1rem;
          overflow-x: auto;
          padding: 1rem;
        }
        
        .kanban-column {
          min-width: 300px;
          background: #f5f5f5;
          border-radius: 8px;
          padding: 1rem;
        }
        
        .task-card {
          background: white;
          border-radius: 4px;
          padding: 0.75rem;
          margin-bottom: 0.5rem;
          box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .priority-high { color: #e74c3c; }
        .priority-medium { color: #f39c12; }
        .priority-low { color: #27ae60; }
      `}</style>
    </div>
  );
}

// Export the component
export default TaskKanbanWidget;

Step 5: Test the Widget

Use the preview feature to test with sample data:

json
{
  "columns": [
    {
      "id": "todo",
      "title": "To Do",
      "tasks": [
        {
          "id": "1",
          "title": "Design mockups",
          "priority": "high",
          "assignee": "John"
        }
      ]
    },
    {
      "id": "in-progress",
      "title": "In Progress",
      "tasks": [
        {
          "id": "2",
          "title": "Implement API",
          "priority": "medium",
          "assignee": "Sarah"
        }
      ]
    },
    {
      "id": "done",
      "title": "Done",
      "tasks": [
        {
          "id": "3",
          "title": "Setup database",
          "priority": "low",
          "assignee": "Mike"
        }
      ]
    }
  ]
}

Step 6: Save and Publish

  1. Click "Save Widget"
  2. Widget is now available for use
  3. Add to peers as needed

Using Widgets in Peers

Step 1: Enable Widget for Peer

  1. Navigate to peer settings
  2. Go to "Widgets" tab
  3. Click "Add Widget"
  4. Select from available widgets
  5. Save configuration

Step 2: Peer Sends Widget

The peer can send widget data in messages:

javascript
// In peer's response
{
  "type": "widget",
  "widgetKey": "task-kanban",
  "data": {
    "columns": [
      // ... widget data
    ]
  }
}

Step 3: Widget Renders

Cognipeer automatically:

  1. Validates data against schema
  2. Loads the widget component
  3. Renders with provided data
  4. Displays in chat interface

Pre-built Widgets

Cognipeer includes several ready-to-use widgets:

1. Sales Funnel Progress

Key: sales-funnel-progress
Purpose: Visualize sales pipeline stages and conversion rates

Data Structure:

json
{
  "stages": [
    {
      "name": "Leads",
      "count": 1500,
      "value": "$150,000",
      "conversionRate": 0.25
    },
    {
      "name": "Qualified",
      "count": 375,
      "value": "$112,500",
      "conversionRate": 0.40
    }
  ],
  "totalValue": "$150,000",
  "conversionRate": 0.10
}

2. Shopping Cart Summary

Key: shopping-cart-summary
Purpose: Display shopping cart with items and totals

Data Structure:

json
{
  "items": [
    {
      "id": "1",
      "name": "Product A",
      "quantity": 2,
      "price": 29.99,
      "image": "https://..."
    }
  ],
  "subtotal": 59.98,
  "tax": 5.40,
  "shipping": 9.99,
  "total": 75.37,
  "currency": "USD"
}

3. Skills Comparison Radar

Key: skills-comparison-radar
Purpose: Compare skill levels across categories

Data Structure:

json
{
  "categories": ["JavaScript", "Python", "React", "Node.js", "SQL"],
  "datasets": [
    {
      "name": "Current Skills",
      "values": [8, 6, 9, 7, 5]
    },
    {
      "name": "Required Skills",
      "values": [9, 8, 9, 8, 7]
    }
  ]
}

4. Support Ticket Overview

Key: support-ticket-overview
Purpose: Display support ticket statistics and priority distribution

Data Structure:

json
{
  "total": 42,
  "open": 15,
  "inProgress": 18,
  "resolved": 9,
  "priorities": {
    "critical": 3,
    "high": 8,
    "medium": 20,
    "low": 11
  },
  "avgResponseTime": "2h 15m"
}

5. User Growth Line Chart

Key: user-growth-line-chart
Purpose: Visualize user growth over time

Data Structure:

json
{
  "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
  "datasets": [
    {
      "name": "New Users",
      "data": [120, 195, 250, 310, 420, 580]
    },
    {
      "name": "Active Users",
      "data": [450, 520, 610, 720, 890, 1050]
    }
  ]
}

6. Weather Daily Highlight

Key: weather-daily-highlight
Purpose: Display weather information with icons

Data Structure:

json
{
  "location": "San Francisco, CA",
  "current": {
    "temp": 68,
    "condition": "Partly Cloudy",
    "humidity": 65,
    "windSpeed": 12
  },
  "forecast": [
    {
      "day": "Monday",
      "high": 72,
      "low": 58,
      "condition": "Sunny"
    }
  ]
}

7. Task Kanban Board

Key: task-kanban
Purpose: Kanban-style task organization

(See full example in Step 4 above)

Widget Development Best Practices

Data Validation

Always define a comprehensive JSON Schema:

json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    // Define all expected properties
  },
  "required": ["essentialField1", "essentialField2"],
  "additionalProperties": false
}

Error Handling

Handle missing or invalid data gracefully:

javascript
function MyWidget({ data }) {
  // Provide defaults
  const {
    title = 'Untitled',
    items = [],
    showLegend = true
  } = data || {};
  
  // Validate critical data
  if (!items || items.length === 0) {
    return <div>No data available</div>;
  }
  
  // Render widget
  return (/* ... */);
}

Performance

  1. Memoize expensive calculations:
javascript
const processedData = useMemo(
  () => processLargeDataset(data),
  [data]
);
  1. Lazy load heavy dependencies:
javascript
const ChartLibrary = lazy(() => import('chart-library'));
  1. Limit re-renders:
javascript
const MemoizedComponent = memo(SubComponent);

Styling

Use inline styles or CSS-in-JS for isolation:

javascript
// Inline styles
<div style={{ color: 'blue', fontSize: '16px' }}>

// CSS-in-JS (styled-jsx)
<style jsx>{`
  .widget { color: blue; }
`}</style>

// Avoid global CSS that might conflict

Accessibility

Make widgets accessible:

javascript
<button
  aria-label="Close widget"
  onClick={handleClose}
  tabIndex={0}
>
  <CloseIcon />
</button>

Security

  1. Sanitize user inputs: Never render raw HTML from untrusted sources
  2. Validate URLs: Check external resource URLs
  3. Limit API calls: Don't make external requests without user consent

Advanced Features

Interactive Widgets

Add user interactions:

javascript
function InteractiveWidget({ data, onAction }) {
  const [selected, setSelected] = useState(null);
  
  const handleClick = (item) => {
    setSelected(item);
    // Notify parent
    onAction?.({
      type: 'itemSelected',
      payload: item
    });
  };
  
  return (/* ... */);
}

Dynamic Data Loading

Fetch additional data if needed:

javascript
function DynamicWidget({ data }) {
  const [details, setDetails] = useState(null);
  
  useEffect(() => {
    if (data.needsDetails) {
      fetch(`/api/details/${data.id}`)
        .then(r => r.json())
        .then(setDetails);
    }
  }, [data]);
  
  return (/* ... */);
}

Responsive Design

Make widgets mobile-friendly:

javascript
function ResponsiveWidget({ data }) {
  const isMobile = useMediaQuery('(max-width: 768px)');
  
  return (
    <div className={isMobile ? 'mobile-layout' : 'desktop-layout'}>
      {/* ... */}
    </div>
  );
}

Widget Management

Organizing Widgets

Use categories and tags:

  • Categories: sales, analytics, productivity, customer-service
  • Tags: Specific keywords for search and filtering

Version Control

Maintain widget versions:

  1. Clone widget before major changes
  2. Test new version separately
  3. Update peers gradually
  4. Keep rollback option

Permissions

Control widget access:

  • WIDGETS_USE_BASIC: Can use widgets in peers
  • WIDGETS_MANAGE: Can create and edit widgets

Troubleshooting

Widget Not Rendering

Possible Causes:

  1. Invalid JSON schema
  2. Data doesn't match schema
  3. Syntax error in component code
  4. Missing required fields

Solutions:

  1. Validate schema at jsonschemavalidator.net
  2. Test with sample data in preview
  3. Check browser console for errors
  4. Review schema requirements

Styling Issues

Problem: Styles not applying or conflicting

Solutions:

  1. Use scoped styles (styled-jsx)
  2. Add unique class prefixes
  3. Use inline styles for critical styling
  4. Check CSS specificity

Performance Issues

Problem: Widget is slow or causes lag

Solutions:

  1. Optimize data processing
  2. Use React.memo for expensive components
  3. Implement virtualization for large lists
  4. Lazy load heavy dependencies

API Integration

Create Widget

javascript
POST /api/v1/widget
{
  "key": "my-widget",
  "name": "My Custom Widget",
  "description": "Description...",
  "category": "analytics",
  "tags": ["custom", "analytics"],
  "schema": { /* JSON Schema */ },
  "component": "/* React component code */"
}

Add Widget to Peer

javascript
POST /api/v1/peer/:peerId/widgets
{
  "widgetId": "widget_123",
  "enabled": true,
  "config": {
    "defaultProps": {}
  }
}

Send Widget in Message

javascript
POST /api/v1/conversation/:conversationId/message
{
  "message": {
    "type": "widget",
    "widgetKey": "sales-funnel-progress",
    "data": {
      "stages": [/* ... */]
    }
  }
}

Summary

The Widget System extends Cognipeer AI's capabilities beyond text, enabling rich, interactive experiences in peer conversations. By creating custom widgets, you can visualize data, build interactive forms, and deliver dynamic content tailored to your specific use cases.

Getting Started:

  1. Explore pre-built widgets
  2. Add widgets to your peers
  3. Test with sample data
  4. Create your first custom widget
  5. Share widgets across your organization

Widgets make your peers more engaging, informative, and powerful.

Built with VitePress