@askdialog/dialog-react

中文文档
3.3.0发布于 2026/10/31TypeScriptESM + CJS零依赖

React component library for Dialog AI-powered product assistance.

原始使用文档
文档目录18 节
  1. Table of contents
  2. Installation
  3. Usage
  4. Available Components
  5. DialogProductBlock
  6. DialogInput
  7. Storefront search
  8. Theming
  9. Development
  10. Prerequisites
  11. Setup
  12. Development Workflows
  13. Build Commands
  14. Project Structure
  15. Testing the Package
  16. Publishing
  17. TypeScript
  18. React Version

@askdialog/dialog-react

React component library for Dialog AI-powered product assistance.

Table of contents

Installation

npm install @askdialog/dialog-react @askdialog/dialog-sdk
# or
pnpm add @askdialog/dialog-react @askdialog/dialog-sdk
# or
yarn add @askdialog/dialog-react @askdialog/dialog-sdk

Usage

import { Dialog } from '@askdialog/dialog-sdk';
import { DialogInput, DialogProductBlock } from '@askdialog/dialog-react';
import '@askdialog/dialog-react/style.css';

const client = new Dialog({
  apiKey: 'your-api-key',
  locale: 'en', currency: 'EUR',
  callbacks: {
    addToCart: () => Promise.resolve(),
    getProduct: () => Promise.resolve({
      // Product data
    }),
  },
});

function App() {
  return (
    <DialogProductBlock
      client={client}
      productId="product-123"
      productTitle="Product Name"
    />
  );
}

Available Components

DialogProductBlock

Product block with up to 2 product questions and an "Ask something else" button that opens the assistant with up to 5 product questions about the product. The button label is in English, French or Spanish depending on the client locale (English otherwise).

Props:

  • client (Dialog) - Dialog SDK client instance (required)
  • productId (string) - Product ID (required)
  • productTitle (string) - Product title (required)
  • selectedVariantId (string, optional) - Selected variant ID
  • enableInput (boolean, optional) - Deprecated. Shows the input field instead of the "Ask something else" button (default: false)

Example:

<DialogProductBlock
  client={client}
  productId="9403924119882"
  productTitle="Blizzard King All-Mountain Snowboard"
  selectedVariantId="variant-123"
/>

DialogInput

Standalone input component for asking questions. It shows the fixed "Ask the AI a question" text and an AI disclosure line, in English, French or Spanish depending on the client locale (English otherwise).

Props:

  • client (Dialog) - Dialog SDK client instance (required)
  • productId (string) - Product ID (required)
  • productTitle (string) - Product title (required)
  • placeholder (string, optional) - Deprecated, ignored
  • selectedVariantId (string, optional) - Selected variant ID

Example:

<DialogInput
  client={client}
  productId="9403924119882"
  productTitle="Product Name"
/>

useDialogSearch binds the search controller of @askdialog/dialog-sdk to component state. The controller holds the search state, the results and the context (language, country, business ranking, texts) and manages requests and analytics; the components render the SDK's connectors (search box, hits, sections, pagination) and handle navigation.

import { Dialog } from '@askdialog/dialog-sdk';
import {
  DialogSearchBar,
  DialogSearchResults,
  useDialogSearch,
} from '@askdialog/dialog-react';
import '@askdialog/dialog-react/style.css';

const client = new Dialog({ apiKey: 'your-api-key', locale: 'en-US', currency: 'USD' });

function SearchPage() {
  const { controller, state, theme } = useDialogSearch({ client, language: 'en', country: 'US' });

  return (
    <>
      <DialogSearchBar controller={controller} placeholder="Search products..." />
      <DialogSearchResults controller={controller} state={state} theme={theme} />
    </>
  );
}

useDialogSearch

Creates one search controller per hook instance and disposes it on unmount. The controller loads the merchant's business ranking and search config with client.apiKey at the first open or search.

Options:

  • client (Dialog) - Dialog SDK client instance (required)
  • language (string, required) - Lowercase ISO 639-1 language code, e.g. fr
  • country (string, required) - Shopper's ISO 3166-1 alpha-2 country, e.g. BE; prices follow its market
  • surface (SearchSurface, optional) - Where results are displayed, for analytics (default: 'search_page')
  • navigate ((url, hit: SearchProductHit) => void, optional) - Router adapter called after selection attribution (e.g. (url) => router.push(url)). Omit it to let the cards' plain <a href> links navigate natively.
  • storefrontRoot (string, optional) - The path a hit's relative _display.url resolves under, e.g. / or /fr-fr/ (Shopify's window.Shopify.routes.root); default /
  • buildProductUrl (deprecated, ignored) - Every hit's link is its _display.url
  • debounceMs (number, optional) - Keystroke debounce (default: 100)
  • hitsPerPage (number, optional) - Results per page (default: 12)
  • sections (SearchSection[], optional) - Extra indices searched alongside the products; collections fills the collections column of DialogSearchResults. Only request an index the catalog exposes: a missing one fails the whole search.

Search language and country are explicit and independent of client.locale, which can be a regional locale such as fr-FR.

Returns: { controller, state, theme } — pass them to the components below.

  • controller (SearchController) - The controller of @askdialog/dialog-sdk; pass it to the SDK's connectors (connectHits(controller), …) to build a custom UI
  • state (SearchSnapshot) - The controller's snapshot, re-rendered on each change: searchState (the query and page asked, keyed by index name), results (status is idle / loading / success / empty / error, products, sections, error) and context (language, country, businessRanking, texts)
  • theme (Theme) - The client's theme, for DialogSearchResults

With the collections column, for a catalog that exposes a collections index:

const { controller, state, theme } = useDialogSearch({
  client,
  language: 'en',
  country: 'US',
  sections: [{ index: 'collections', hitsPerPage: 5 }],
});

DialogSearchBar

Search input bound to the search box connector: its value is the controller's query, typing runs a debounced search, submitting (Enter) searches immediately. Focusing the input opens the search, which emits the TRACK_OPENED_SEARCH analytics event and runs the empty-query search.

Props:

  • controller (SearchController) - From useDialogSearch (required)
  • placeholder (string, optional) - Input placeholder text
  • autoFocus (boolean, optional) - Focus the input on mount
  • submitAriaLabel (string, optional) - Accessible label of the submit button (default: 'Search')

DialogSearchResults

Floating results panel overlaying the page content: portaled to document.body in position: fixed, centered on the bar (up to 1440px wide, filling the viewport) and anchored under the spot where the component is rendered (place it right after the bar), so no ancestor stacking context or overflow: hidden can hide it. It shows the same layout as the Shopify search overlay: a collections column on the left when sections requests them, the products on the right as a list or a 3-column grid, the query match emphasized in every title, and, when seeAllHref is set, a "See all results" button; without it, the panel shows the first page of hits only and does not paginate. Below 768px the panel stacks, collections in a horizontal rail above the products. Colors, radii and font follow the SDK theme (dark palette when backgroundColor is dark, straight or rounded corners from ctaBorderType). Each product card renders the hits connector's display of the hit, Algolia's Shopify record: its _display.image (hits require _display, computed by the server since DAT-2016; when _display.image is absent, no thumbnail; its shape draws it with the theme's corners for theme, straight corners for square, rounded corners for rounded and as a circle for round), its _display.title, its _display.price (formatted by the server in the shopper's market currency), struck through next to it its _display.compare_at_price when present, and its _display.url (a relative one resolved under storefrontRoot); a hit without a price shows none. Each card links to the product page and records search attribution (viewport impressions, select on click and middle-click) automatically. Clicking outside the panel (and outside the bar) closes it; typing again or re-focusing the bar reopens it with the results kept.

Props:

  • controller (SearchController) - From useDialogSearch (required)
  • state (SearchSnapshot) - From useDialogSearch (required)
  • locale (string, optional) - BCP 47 locale for counts and labels; omitted, the connectors' display is used, in the search language. Prices are formatted by the server.
  • theme (Theme, optional) - The client's theme, as returned by useDialogSearch; styles the panel (palette, radii, font)
  • layout ('list' | 'grid', optional) - Products layout (default: 'list')
  • seeAllHref ((query) => string, optional) - Link of the "See all results" footer button; omitted, the panel shows the first page of hits only, with no pagination

DialogSearchPagination

Previous/next controls with a page indicator, bound to the pagination connector; hidden while loading and while there is a single page. Not rendered by DialogSearchResults, which does not paginate: use it on a results page of your own.

Props:

  • controller (SearchController) - From useDialogSearch (required)
  • state (SearchSnapshot) - From useDialogSearch (required)
  • locale (string, optional) - Locale of the button labels; the search language when omitted

DialogSearchProductCard

One product card, as DialogSearchResults renders it, for custom layouts. It renders the hits connector's display of state.results.products.hits[index] and records its impressions and selection; it renders nothing for a hit that is not at index in the shown results.

Props:

  • controller (SearchController) - From useDialogSearch (required)
  • hit (SearchProductHit) - state.results.products.hits[index] (required)
  • index (number) - The hit's position in the shown results (required)

Upgrading from 2.x

The components keep their props and rendering, except the pagination of DialogSearchResults; useDialogSearch keeps its options. What changed:

  • DialogSearchResults no longer paginates: without seeAllHref it shows the first page of hits only. Set seeAllHref, or render DialogSearchPagination on a results page of your own.
  • controller is the controller of @askdialog/dialog-sdk: setQuery, submit and setPage are replaced by setSearchState and search (or the SDK's connectors), getState by getSnapshot, observeResult / selectResult by observeHit / selectHit.
  • state is the controller's snapshot: read state.results.status, state.results.products and state.results.sections instead of state.status, state.response and state.sections, and state.context.businessRanking instead of state.businessRanking.
  • Without a locale prop, texts and prices follow the search language and country instead of English and the browser's number format.
  • The peer @askdialog/dialog-sdk is 3.x.

Theming

The components use CSS variables for theming. You can customize the theme through the Dialog SDK client:

const client = new Dialog({
  apiKey: 'your-api-key',
  theme: {
    backgroundColor: 'pink',
    primaryColor: 'pink',
    ctaTextColor: 'white',
    ctaBorderType: 'rounded',
    capitalizeCtas: true,
    fontFamily: 'Arial',
    highlightProductName: true,
    title: {
      fontSize: '22px',
      color: 'purple',
    },
    description: {
      color: 'blue',
      fontSize: '18px',
    },
    content: {
      color: 'green',
      fontSize: '10px',
    },
  },
});

Development

This section is for contributors working on the library itself.

Prerequisites

  • Node.js >= 22
  • pnpm >= 10

Setup

# From monorepo root
pnpm install

Development Workflows

Daily Development

Work on components with instant feedback:

# From monorepo root
pnpm dev:react-example
# Opens react-example app at http://localhost:5173

What happens:

  • The example app runs with Vite dev server
  • Components are resolved from source files (packages/react/src/) via alias
  • Changes to components are immediately reflected (HMR enabled)
  • No rebuild required

Testing Built Library

Test the library as consumers would receive it from npm:

# Step 1: Build the library
pnpm build:react

# Step 2: Run example app against built dist/
cd packages/react-example
pnpm dev:test-dist
# Or from root: TEST_DIST=true pnpm dev:react-example

When to use:

  • Before creating a pull request
  • After modifying build configuration
  • To verify the build works correctly
  • Before publishing a new version

Build Commands

# Build the library only
pnpm build:react

# Build all packages in the monorepo
pnpm build

# Clean dist folder
pnpm --filter @askdialog/dialog-react clean

# Lint code
pnpm --filter @askdialog/dialog-react lint

# Fix linting issues
pnpm --filter @askdialog/dialog-react lint:fix

Project Structure

packages/react/
├── src/
│   ├── main.ts              # Library entry point
│   ├── components/          # Exported components
│   │   ├── index.ts         # Component barrel export
│   │   └── DialogProductBlock/
│   │       ├── DialogProductBlock.tsx
│   │       ├── DialogProductBlock.css
│   │       ├── DialogInput.tsx
│   │       ├── DialogInput.css
│   │       ├── ThemeProvider.tsx
│   │       └── ...
│   └── icons/               # Icon components
├── dist/                    # Build output (gitignored)
├── package.json
├── vite.config.ts           # Library build configuration
└── project.json             # Nx configuration

Testing the Package

Full Integration Test

Test the package in a real React project:

# 1. Build and pack
cd packages/react
pnpm build
pnpm pack

# 2. Create test project
cd /tmp
pnpm create vite test-dialog --template react-ts
cd test-dialog
pnpm install

# 3. Install from tarball
pnpm add /path/to/askdialog-dialog-react-*.tgz

# 4. Test imports and functionality
pnpm dev

Publishing

# From monorepo root
pnpm publish:react

Pre-publish checklist:

  • All tests pass
  • Version updated in package.json
  • Tested with built library (pnpm dev:test-dist)
  • Tarball inspected with pnpm pack
  • CHANGELOG updated

TypeScript

This package includes TypeScript type definitions. The types are automatically available when you install the package.

React Version

This package requires React 19 or higher as a peer dependency.

版本与发布记录

@askdialog/dialog-react 共发布 107 个版本,首次发布于 2025/11/27;过去 12 个月发布了 107 个版本。

版本发布日期距今
3.3.0latest2026/10/312 天前
0.0.0-beta-20261031113506beta2026/10/313 天前
3.2.02026/10/313 天前
0.0.0-beta-202610301831342026/10/313 天前
3.1.02026/10/303 天前
0.0.0-beta-202610301331332026/10/303 天前

关于 @askdialog/dialog-react 的常见问题

@askdialog/dialog-react 是什么?

用于Dialog ai产品辅助的React组件库。

如何安装 @askdialog/dialog-react?

在项目目录运行 npm install @askdialog/dialog-react,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^19.0.0)、react-dom(^19.0.0)、@askdialog/dialog-sdk(^3.1.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@askdialog/dialog-react 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@askdialog/dialog-react 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@askdialog/dialog-react 可以商用吗?

@askdialog/dialog-react 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@askdialog/dialog-react 还在维护吗?

最新版本 3.3.0 发布于 2026/10/31(2 天前);至今共发布 107 个版本,其中过去 12 个月发布了 107 个;首次发布于 2025/11/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。