npm package: @kenzi-wealth/widget
Description: The Kenzi Widget for smart conversations, AI-enabled analysis and investment intelligence for your investment portfolio.
Author: Nikki Strømsnes
Latest version: 0.12.0

# Kenzi Widget

This is the Kenzi widget for smart conversations, AI-enabled analysis and investment intelligence for your investment portfolio.

See more on our website: [https://kenziwealth.com/](https://kenziwealth.com/) or reach out for a demo on [contact@kenziwealth.com](mailto:contact@kenziwealth.com).

## Requirements

- **React** 18 or 19 (`react` and `react-dom`)
- A bundler that supports ES modules (Vite, webpack, esbuild, etc.)

## Installation

```sh
npm install @kenzi-wealth/widget
```

```sh
yarn add @kenzi-wealth/widget
```

```sh
pnpm add @kenzi-wealth/widget
```

## Quick Start

Render the `<Widget />` component anywhere in your app. CSS is bundled and injected automatically — no separate stylesheet import is needed.

```tsx
import { Widget } from '@kenzi-wealth/widget'

const App = () => <Widget />
```

This renders the chat prompt input and intelligence card. When a user submits a message, the chat dialog opens with the conversation.

## API

### `<Widget />`

The main chat widget. Renders the prompt input, intelligence card, and chat dialog. Place it once in your component tree.

`Widget` accepts no props. All programmatic control is handled through `useKenzi` or `KenziTrigger`.

```tsx
import { Widget } from '@kenzi-wealth/widget'

const App = () => (
	<main>
		<h1>My App</h1>
		<Widget />
	</main>
)
```

### `<KenziTrigger />`

A button that opens the chat dialog when clicked. Renders a native `<button type="button">` element with no default styling, so it can be styled freely.

#### Props

| Prop        | Type                    | Default  | Description                                    |
| ----------- | ----------------------- | -------- | ---------------------------------------------- |
| `children`  | `JSX.Element \| string` | `"Chat"` | Custom label for the trigger button.           |
| `className` | `string`                | —        | Optional CSS class name applied to the button. |

#### Examples

With a custom label:

```tsx
import { Widget, KenziTrigger } from '@kenzi-wealth/widget'

const App = () => (
	<>
		<KenziTrigger>Ask Kenzi</KenziTrigger>
		<Widget />
	</>
)
```

With custom styling:

```tsx
<KenziTrigger className="my-chat-button">
	<img src="/chat-icon.svg" alt="" /> Chat with us
</KenziTrigger>
```

With no children (renders "Chat" by default):

```tsx
<KenziTrigger />
```

### `useKenzi()`

A React hook for programmatic control of the chat widget. Must be called within a component tree that also renders `<Widget />`.

#### Return value

```typescript
type UseKenzi = {
	isOpen: boolean
	open: () => void
	close: () => void
}
```

| Property | Type         | Description                                                             |
| -------- | ------------ | ----------------------------------------------------------------------- |
| `isOpen` | `boolean`    | Reactive — whether the chat dialog is currently open.                   |
| `open`   | `() => void` | Opens the chat dialog with a view transition. No-op if already open.    |
| `close`  | `() => void` | Closes the chat dialog with a view transition. No-op if already closed. |

Both `open` and `close` are stable references (they do not change between renders), so they are safe to pass as props or use in dependency arrays.

#### Examples

Toggle button:

```tsx
import { useKenzi } from '@kenzi-wealth/widget'

const ChatToggle = () => {
	const { isOpen, open, close } = useKenzi()

	return (
		<button onClick={isOpen ? close : open}>
			{isOpen ? 'Close chat' : 'Open chat'}
		</button>
	)
}
```

Open on an external event:

```tsx
import { useEffect } from 'react'
import { useKenzi } from '@kenzi-wealth/widget'

const AutoOpen = ({ shouldOpen }: { shouldOpen: boolean }) => {
	const { open } = useKenzi()

	useEffect(() => {
		if (shouldOpen) open()
	}, [shouldOpen, open])

	return null
}
```

Full integration:

```tsx
import { Widget, KenziTrigger, useKenzi } from '@kenzi-wealth/widget'

const OpenChatButton = () => {
	const { open } = useKenzi()

	return (
		<button type="button" onClick={open}>
			Open programmatically
		</button>
	)
}

const App = () => (
	<>
		<KenziTrigger>Ask Kenzi</KenziTrigger>
		<OpenChatButton />
		<Widget />
	</>
)
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md).