@kenzi-wealth/widget-native
v0.2.3
Published
The Kenzi Widget for smart conversations, AI-enabled analysis and investment intelligence for your investment portfolio.
Readme
Kenzi Widget (React Native)
The React Native SDK for the Kenzi widget — smart conversations, AI-enabled analysis, and investment intelligence for your investment portfolio.
See more on our website: https://kenziwealth.com/ or reach out for a demo on [email protected].
Requirements
- React 18 or later
- React Native 0.70 or later
- Peer dependencies:
jotai≥ 2.19,react-native-svg≥ 15 - Works with both bare React Native and Expo (managed and bare workflows). No native code — no pod install or custom dev build required.
Installation
npm install @kenzi-wealth/widget-nativeyarn add @kenzi-wealth/widget-nativepnpm add @kenzi-wealth/widget-nativeQuick Start
Render the <Widget /> component anywhere in your app and pass a trigger as its child. The trigger is shown when the chat is closed; when activated, it opens the chat dialog.
import { Text } from 'react-native'
import { Widget, KenziTrigger } from '@kenzi-wealth/widget-native'
const App = () => (
<Widget>
<KenziTrigger>
<Text>Ask Kenzi</Text>
</KenziTrigger>
</Widget>
)API
<Widget />
The main chat widget. Renders the chat dialog, prompt input, guided actions, and trade confirmation flow. Place it once in your component tree.
Props
| Prop | Type | Default | Description |
| ------------------ | ----------- | ------- | ------------------------------------------------------------------------- |
| children | ReactNode | — | Content rendered when the chat is closed. Typically a <KenziTrigger />. |
| persistentPrompt | boolean | false | When true, the prompt input is rendered even while the chat is closed. |
Examples
With a trigger button:
import { Widget, KenziTrigger } from '@kenzi-wealth/widget-native'
const App = () => (
<Widget>
<KenziTrigger>
<Text>Ask Kenzi</Text>
</KenziTrigger>
</Widget>
)With a persistent prompt input:
<Widget persistentPrompt>
<KenziTrigger>
<Text>Ask Kenzi</Text>
</KenziTrigger>
</Widget><KenziTrigger />
An unstyled Pressable that opens the chat when activated. Accepts all standard PressableProps — supply your own style and children to control the visuals (wrap text in a React Native <Text> as usual).
Props
Extends PressableProps (with onPress overridden):
| Prop | Type | Description |
| --------- | ------------ | --------------------------------------------------- |
| onPress | () => void | Called immediately before the chat opens. Optional. |
Examples
With a custom label and styling:
import { Text } from 'react-native'
import { KenziTrigger } from '@kenzi-wealth/widget-native'
const Trigger = () => (
<KenziTrigger style={styles.trigger}>
<Text style={styles.triggerLabel}>Ask Kenzi</Text>
</KenziTrigger>
)Running side effects when the chat opens:
<KenziTrigger onPress={() => trackEvent('chat_opened')}>
<Text>Chat</Text>
</KenziTrigger><InvestmentHealthCard />
A pressable card that displays the user's investment health score with an animated circular gauge. Tapping the card opens the chat with a prefilled analysis flow.
Props
| Prop | Type | Default | Description |
| --------- | ------------------------ | ----------- | ---------------------------------------------------------------- |
| variant | 'default' \| 'compact' | 'default' | 'compact' hides the description text and keeps only the gauge. |
import { InvestmentHealthCard } from '@kenzi-wealth/widget-native'
const Cards = () => (
<>
<InvestmentHealthCard />
<InvestmentHealthCard variant="compact" />
</>
)<TradeIntentCard />
A pressable card highlighting a suggested trade with a match score. Tapping the card opens the chat with a prefilled trade-intent flow seeded with the configured instrument.
Props
| Prop | Type | Default | Description |
| ---------------- | ------------------ | ------------------------- | -------------------------------------------------------------------------------------- |
| title | string | — | Card heading, e.g. "Investment Intelligence". |
| match | number | — | Match score, rendered as {match}% match. |
| ticker | string | — | Instrument ticker symbol (e.g. "Z74"). Carried into the chat and the trade order. |
| name | string | — | Instrument display name (e.g. "Singtel"). Used in the body, prompts, and trade copy. |
| price | number | — | Price per share in the instrument's currency. |
| description | string | name-interpolated default | Short explanation shown beneath the title. |
| instrumentType | 'Stock' \| 'ETF' | 'Stock' | Instrument type. Flows into the trade order on confirmation. |
| lotSize | number | 1 | Minimum tradable share increment (e.g. 100 for Bursa/KLS board lots). |
Examples
Minimum configuration — the card renders a default name-interpolated description:
import { TradeIntentCard } from '@kenzi-wealth/widget-native'
const Suggestion = () => (
<TradeIntentCard
title="Investment Intelligence"
match={98}
ticker="Z74"
name="Singtel"
price={4.9}
/>
)With a custom description and Bursa/KLS board lot:
<TradeIntentCard
title="Investment Intelligence"
match={98}
ticker="Z74"
name="Singtel"
price={4.9}
lotSize={100}
description="Singtel adds growth potential and some extra swings."
/>For an ETF:
<TradeIntentCard
title="Investment Intelligence"
match={92}
ticker="SPY"
name="SPDR S&P 500 ETF"
price={500}
instrumentType="ETF"
/>useKenzi()
A React hook for programmatic control of the chat widget. Must be called within a component tree that also renders <Widget />.
Return value
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. No-op if already open. |
| close | () => void | Closes the chat dialog. No-op if already closed. |
open and close are stable references, safe to pass as props or use in dependency arrays.
Example
import { Pressable, Text } from 'react-native'
import { useKenzi } from '@kenzi-wealth/widget-native'
const ChatToggle = () => {
const { isOpen, open, close } = useKenzi()
return (
<Pressable onPress={isOpen ? close : open}>
<Text>{isOpen ? 'Close chat' : 'Open chat'}</Text>
</Pressable>
)
}