npm package: @opendatalabs/vana-react
Description: React hooks and components for Vana Network
Author: OpenDataLabs
Latest version: 3.1.0

# @opendatalabs/vana-react

React hooks and components for integrating with the Vana Network.

[![npm version](https://img.shields.io/npm/v/@opendatalabs/vana-react.svg)](https://www.npmjs.com/package/@opendatalabs/vana-react)
[![Documentation](https://img.shields.io/badge/docs-typedoc-blue.svg)](https://vana-com.github.io/vana-app/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Production-ready React components for Vana App builders

Drop in secure, type-safe data upload and social sharing instead of building
custom iframe integrations, managing authentication, or writing boilerplate
message protocols.

**Solves:**

- Cross-origin iframe communication (we handle postMessage + origin validation)
- Wallet authentication flows (pre-built, tested, Vana Network–compatible)
- Data schema validation and upload (error handling included)
- Social sharing with copy-to-clipboard (works everywhere)

**Tightly integrated with Vana App infrastructure** – components point to
`app.vana.com` and handle all the plumbing.

```bash
npm install @opendatalabs/vana-react
# or
yarn add @opendatalabs/vana-react
# or
pnpm add @opendatalabs/vana-react
```

## Components

### VanaAppUploadWidget

An embeddable iframe widget that facilitates data upload operations for Vana
Apps.

#### VanaAppUploadWidget Features

- Cross-origin secure message communication
- Wallet authentication support
- Data upload with schema validation
- Theme customization (CSS custom properties)
- Full-viewport overlay (resize postMessage ignored/deprecated)
- TypeScript support

#### VanaAppUploadWidget Usage

```tsx
import { VanaAppUploadWidget } from "@opendatalabs/vana-react";

function App() {
  const handleResult = (result: any) => {
    console.log("Upload successful:", result);
  };

  const handleError = (error: string) => {
    console.error("Upload error:", error);
  };

  const handleAuth = (walletAddress: string) => {
    console.log("Authenticated:", walletAddress);
  };

  return (
    <VanaAppUploadWidget
      appId="your-app-id"
      onResult={handleResult}
      onError={handleError}
      onAuth={handleAuth}
      schemaId={123}
      prompt="Upload your data"
      operation="prompt_gemini_agent"
      operationParams={{ goal: "Analyze user data" }}
      theme={{ "--primary": "#007bff" }}
      isOpen={true}
      onClose={() => console.log("Widget closed")}
    />
  );
}
```

#### VanaAppUploadWidget Props

| Prop              | Type                                   | Required | Default                | Description                                                            |
| ----------------- | -------------------------------------- | -------- | ---------------------- | ---------------------------------------------------------------------- |
| `appId`           | `string`                               | Yes      | -                      | Your Vana application ID                                               |
| `onResult`        | `(data: AgentOperationResult) => void` | Yes      | -                      | Callback when data upload completes successfully                       |
| `onError`         | `(error: string) => void`              | Yes      | -                      | Callback when an error occurs                                          |
| `onAuth`          | `(walletAddress: string) => void`      | Yes      | -                      | Callback when wallet authentication succeeds                           |
| `isOpen`          | `boolean`                              | No       | `true`                 | Controls visibility; iframe stays mounted for prefetching (fullscreen) |
| `onClose`         | `() => void`                           | No       | -                      | Fires when child posts `uploader:closed`                               |
| `onReady`         | `() => void`                           | No       | -                      | Fires after child `ready` and config sent; safe for animation timing   |
| `iframeOrigin`    | `string`                               | No       | `https://app.vana.com` | Origin URL for the iframe                                              |
| `schemaId`        | `number`                               | No       | -                      | Schema ID for data validation                                          |
| `prompt`          | `string`                               | No       | -                      | LLM inference prompt (legacy; prefer `operation` + `operationParams`)  |
| `operation`       | `string`                               | No       | -                      | Agent operation (e.g. `prompt_gemini_agent`, `llm_inference`)          |
| `operationParams` | `Record<string, unknown>`              | No       | -                      | Params forwarded to personal server with the operation                 |
| `filters`         | `Record<string, string>`               | No       | -                      | JSONPath filters per schema for data pre-filtering                     |
| `theme`           | `VanaAppUploadTheme`                   | No       | -                      | CSS custom properties (e.g. `{ "--primary": "#6366f1" }`)              |
| `zIndex`          | `number`                               | No       | `1000`                 | Z-index for stacking control                                           |

#### Ref API

The `VanaAppUploadWidget` component supports React `forwardRef` to expose the
underlying iframe element:

```tsx
const iframeRef = useRef<HTMLIFrameElement>(null);

<VanaAppUploadWidget
  ref={iframeRef}
  appId="your-app-id"
  {...otherProps}
/>

// Access iframe programmatically
iframeRef.current?.contentWindow?.postMessage(...);
```

#### Security Considerations

**Origin Validation**: The widget validates the iframe's origin on the first
`ready` message before posting configuration. This protects against:

- Proxy/redirect chains that change the iframe's origin unexpectedly
- CSRF-style attacks via compromised iframe sources
- Message forwarding attacks (relay messages are filtered to "session"-only
  payloads)

Always use `https://app.vana.com` (or your authenticated domain) as the
`iframeOrigin` prop. If you need to redirect or proxy the iframe, ensure the
final destination origin matches your security policy.

#### Deprecated Props

- `className`: No longer used; widget layout is fully controlled internally for
  fullscreen experience. Accepted for backward compatibility but has no effect.
- `resize` postMessage: Ignored; widget is full-viewport by design. Height
  adjustment via postMessage is no longer supported.

### VanaAppSocialShareWidget

A customizable social sharing component designed for Vana Data Apps. Provides
seamless sharing to social platforms with copy-to-clipboard functionality and
countdown notifications.

#### VanaAppSocialShareWidget Features

- One-click sharing to Twitter, Facebook, LinkedIn, and Instagram
- Copy-to-clipboard with automatic countdown timer
- Theme customization with icon sizing
- Flexible text generation with emojis and funny notes
- Toast notifications with progress indicator
- TypeScript support with full type definitions
- Zero external UI dependencies

#### VanaAppSocialShareWidget Usage

```tsx
import { VanaAppSocialShareWidget } from "@opendatalabs/vana-react";

function MyDataApp() {
  const handleShare = (platform: string) => {
    console.log(`User shared on ${platform}`);
  };
  return (
    <VanaAppSocialShareWidget
      appName="Ice Cream Flavor"
      shareContent="ChocoVision Leader (Dark Chocolate)"
      shareEmoji="🍦"
      funnyNote="Apparently I'm in the same league as Beyoncé!"
      title="Share your flavor"
      onShare={handleShare}
      classNames={{
        root: "text-center",
        button: "w-12 h-12 rounded-full bg-white shadow-md hover:scale-105",
      }}
      theme={{ iconSize: 20 }}
    />
  );
}
```

#### VanaAppSocialShareWidget Props

| Prop              | Type                                    | Required | Default                | Description                                      |
| ----------------- | --------------------------------------- | -------- | ---------------------- | ------------------------------------------------ |
| `appName`         | `string`                                | Yes      | -                      | Name of your Vana app (e.g., "Ice Cream Flavor") |
| `shareContent`    | `string`                                | Yes      | -                      | Main content to share (e.g., user's result)      |
| `shareEmoji`      | `string`                                | No       | -                      | Emoji to prepend to share content                |
| `funnyNote`       | `string`                                | No       | -                      | Engaging note to add after content               |
| `title`           | `string`                                | No       | `"Share"`              | Title displayed above share buttons              |
| `callToAction`    | `string`                                | No       | `"Try @ app.vana.com"` | CTA text in share message                        |
| `hashtag`         | `string`                                | No       | `"#DATAREVOLUTION"`    | Hashtag to append to message                     |
| `theme`           | `VanaAppSocialShareTheme`               | No       | `{}`                   | Theme configuration (iconSize)                   |
| `onShare`         | `(platform: SocialPlatform) => void`    | No       | -                      | Callback when user shares                        |
| `onShowToast`     | `(message: ToastMessage) => void`       | No       | -                      | Custom toast handler (uses internal if not set)  |
| `classNames`      | `VanaAppSocialShareClassNames`          | No       | `{}`                   | Class names for all component parts              |
| `hideTitle`       | `boolean`                               | No       | `false`                | Hide the title section                           |
| `renderButton`    | `(platform, Icon) => ReactNode`         | No       | -                      | Custom render function for buttons               |
| `buttonComponent` | `React.ComponentType<ShareButtonProps>` | No       | -                      | Custom button component                          |

#### ClassNames Options

| Property       | Type     | Description                                     |
| -------------- | -------- | ----------------------------------------------- |
| `root`         | `string` | Root container class                            |
| `title`        | `string` | Title section class (includes icon and text)    |
| `buttons`      | `string` | Buttons container class                         |
| `button`       | `string` | Base class for all buttons                      |
| `toast`        | `string` | Toast container class (if using internal toast) |
| `toastContent` | `string` | Toast content wrapper class                     |
| `progress`     | `string` | Progress bar class for countdown                |

# Run development build with watch mode

npm run dev

# Run tests

npm test

# Build for production

npm run build

# Run linting

npm run lint

# Type checking

npm run typecheck

### Testing

## License

MIT © OpenDataLabs