npm package: @nexvio-ai/widget-js
Description: Embeddable Nexvio chat widget custom element and React bindings.
Author: Nexvio
Latest version: 0.1.0

# Nexvio Widget JS

Embeddable JavaScript SDK that renders the Nexvio chat experience inside any web
application. The package exposes two custom elements:

- `<nexvio-chat-widget>` - Direct widget embed (for custom integrations)
- `<nexvio-chat-bot>` - Floating chat button with animated widget (recommended)

Plus React bindings for developers who prefer declarative integrations.

## Installation

```bash
pnpm add @nexvio-ai/widget-js
```

The package ships ESM, CJS, and type declarations. React bindings are exposed
via the `@nexvio-ai/widget-js/react` subpath export.

## Quick Start

### Using `<nexvio-chat-bot>` (Recommended)

The easiest way to add a chat widget to your site is using `<nexvio-chat-bot>`, which
provides a floating chat button and automatically manages the widget container.

```ts
import '@nexvio-ai/widget-js';

const chatbot = document.createElement('nexvio-chat-bot');
chatbot.setOptions({ publicKey: 'pk_test-123' });
document.body.append(chatbot);
```

**React:**

```tsx
import { NexvioChatbot } from '@nexvio-ai/widget-js/react';

export function App() {
  return (
    <NexvioChatbot
      options={{
        publicKey: 'pk_test-123',
        onEvent: (event) => console.log(event.name, event.detail),
      }}
    />
  );
}
```

### Using `<nexvio-chat-widget>` (Advanced)

For custom integrations where you want full control over the widget container,
use `<nexvio-chat-widget>` directly.

```ts
import '@nexvio-ai/widget-js';

const widget = document.createElement('nexvio-chat-widget');
widget.setOptions({ publicKey: 'pk_test-123' });
document.body.append(widget);
```

**React:**

```tsx
import { NexvioWidget } from '@nexvio-ai/widget-js/react';

export function SupportWidget() {
  return (
    <NexvioWidget
      options={{
        publicKey: 'pk_test-123',
        onEvent: (event) => console.log(event.name, event.detail),
      }}
      className="h-full w-full"
    />
  );
}
```

## `<nexvio-chat-bot>` Options

The chatbot element extends all widget options and adds the following:

### Chatbot-Specific Options

- `position` (`'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'`) - Position of the chat button. Default: `'bottom-right'`
- `defaultOpen` (`boolean`) - Whether the widget should be open initially. Default: `false`
- `buttonColor` (`string`) - Background color of the chat button. Default: `'#3B82F6'`
- `badge` (`number | boolean`) - Show a notification badge. Pass a number for unread count, or `true` for a dot. Default: `false`
- `buttonIcon` (`string`) - Custom SVG icon for the button (replaces default chat icon)
- `gap` (`number`) - Gap from screen edge in pixels. Default: `20`

### Widget Options (Inherited)

All options from `<nexvio-chat-widget>` are supported:

- `publicKey` (required) – widget identifier used by the Nexvio platform
- `appearance` – overrides for colours, fonts, or density. Values are passed to the hosted widget frame
- `metadata` / `context` – arbitrary JSON forwarded downstream
- `clientActions` – map of callbacks that can be invoked by the iframe for client-side behaviour (e.g. analytics, navigation)
- `onEvent` – receives all events emitted by the widget (ready, error, custom events defined in the workspace)
- `fetch` – custom `fetch` implementation used when the frame requests server-side actions through the host
- `client.tools` – client-side tools that can be called by the AI
- `startScreen` – configuration for the initial greeting screen

### Example: Full Configuration

```ts
const chatbot = document.createElement('nexvio-chat-bot');
chatbot.setOptions({
  publicKey: 'pk_test-123',
  position: 'bottom-right',
  buttonColor: '#6366F1',
  badge: 3, // Show unread count
  defaultOpen: false,
  gap: 24,
  appearance: {
    colorScheme: 'light',
  },
  context: {
    visitor: {
      name: 'John Doe',
      email: 'john@example.com',
    },
  },
  onEvent: (event) => {
    console.log('Widget event:', event.name, event.detail);
  },
});
document.body.append(chatbot);
```

## Programmatic Control

### Methods

```ts
const chatbot = document.querySelector('nexvio-chat-bot');

// Open the widget
chatbot.open();

// Close the widget
chatbot.close();

// Toggle open/closed state
chatbot.toggle();

// Check if open
console.log(chatbot.isOpen); // boolean

// Access the underlying widget element
const widget = chatbot.widget;
widget?.focusInput();
widget?.setVisitor({ name: 'Jane Doe' });
```

### Events

```ts
const chatbot = document.querySelector('nexvio-chat-bot');

// Listen to chatbot-specific events
chatbot.addEventListener('chatbot.opened', () => {
  console.log('Chat opened');
});

chatbot.addEventListener('chatbot.closed', () => {
  console.log('Chat closed');
});

// Listen to widget events (forwarded from the widget)
chatbot.addEventListener('nexvio.event', (event) => {
  console.log('Widget event:', event.detail);
});
```

## React Usage

### Basic Example

```tsx
import { NexvioChatbot } from '@nexvio-ai/widget-js/react';
import { useRef } from 'react';

export function App() {
  const chatbotRef = useRef<NexvioChatbotElement>(null);

  return (
    <>
      <button onClick={() => chatbotRef.current?.open()}>
        Open Chat
      </button>

      <NexvioChatbot
        ref={chatbotRef}
        options={{
          publicKey: 'pk_test-123',
          buttonColor: '#6366F1',
          badge: 3,
        }}
      />
    </>
  );
}
```

### With Event Handling

```tsx
import { NexvioChatbot } from '@nexvio-ai/widget-js/react';
import type { NexvioWidgetEvent } from '@nexvio-ai/widget-js';

export function App() {
  const handleEvent = (event: NexvioWidgetEvent) => {
    console.log('Event:', event.name, event.detail);
  };

  return (
    <NexvioChatbot
      options={{
        publicKey: 'pk_test-123',
        onEvent: handleEvent,
        appearance: {
          colorScheme: 'dark',
        },
      }}
    />
  );
}
```

### Using the Hook

```tsx
import { useNexvioChatbot } from '@nexvio-ai/widget-js/react';
import { useEffect } from 'react';

export function App() {
  const { ref, setElement } = useNexvioChatbot({
    publicKey: 'pk_test-123',
    buttonColor: '#6366F1',
  });

  useEffect(() => {
    // Access the element via ref.current
    const chatbot = ref.current;
    if (chatbot) {
      chatbot.open();
    }
  }, []);

  return <nexvio-chat-bot ref={setElement} />;
}
```

## `<nexvio-chat-widget>` Options

For direct widget usage, see the widget-specific options:

- `publicKey` (required) – widget identifier used by the Nexvio platform
- `appearance` – overrides for colours, fonts, or density. Values are passed to the hosted widget frame
- `metadata` / `context` – arbitrary JSON forwarded downstream
- `clientActions` – map of callbacks that can be invoked by the iframe for client-side behaviour (e.g. analytics, navigation)
- `onEvent` – receives all events emitted by the widget (ready, error, custom events defined in the workspace)
- `fetch` – custom `fetch` implementation used when the frame requests server-side actions through the host
- `messageActions` – per-message UI action toggles (copy, feedback, retry)
- `client.tools` – client-side tools that can be called by the AI
- `startScreen` – configuration for the initial greeting screen

## Styling

### CSS Custom Properties

The chatbot element exposes CSS custom properties for styling:

```css
nexvio-chat-bot {
  --chatbot-button-size: 60px;
  --chatbot-button-bg: #3B82F6;
  --chatbot-button-color: white;
  --chatbot-widget-width: 420px;
  --chatbot-widget-height: 600px;
  --chatbot-widget-gap: 20px;
}
```

### Responsive Behavior

On mobile devices (screen width ≤ 768px), the widget automatically switches to full-screen mode for better usability.

## Development

```bash
pnpm install
pnpm --filter @nexvio-ai/widget-js test
pnpm --filter @nexvio-ai/widget-js build
```

The build pipeline uses `tsup` to emit bundled ESM/CJS outputs with type
declarations. Vitest covers the base utilities used to exchange data with the
hosted iframe.

## Demo Integration

The monorepo includes a live integration at
`apps/demo-app/src/app/widget/page.tsx`. Launch it with:

```bash
pnpm --filter demo-app dev
```

The demo renders `<NexvioWidget />`, lets you swap the widget public key, and
mirrors all bridge events in a side panel so you can validate host/widget
communication in real time.

## Migration Guide

### From `<nexvio-chat-widget>` to `<nexvio-chat-bot>`

If you're currently using `<nexvio-chat-widget>` and want to switch to the chatbot:

**Before:**
```ts
const widget = document.createElement('nexvio-chat-widget');
widget.setOptions({ publicKey: 'pk_test-123' });
document.body.append(widget);
```

**After:**
```ts
const chatbot = document.createElement('nexvio-chat-bot');
chatbot.setOptions({ publicKey: 'pk_test-123' });
document.body.append(chatbot);
```

All widget options work the same way. The chatbot automatically creates and manages the widget internally.

## TypeScript Support

Full TypeScript support is included:

```ts
import type {
  NexvioWidgetOptions,
  NexvioWidgetEvent,
  NexvioChatbotOptions,
} from '@nexvio-ai/widget-js';
import type { NexvioChatbotElement } from '@nexvio-ai/widget-js';
```

## Browser Support

- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)

Requires support for:
- Custom Elements (Web Components)
- Shadow DOM
- ES2017+ features