@bluprynt/forms-viewer

中文文档
4.2.0发布于 2026/10/21TypeScriptESM + CJS零依赖近 30 天下载 2.1万

Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with @bluprynt/forms-core to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.

原始使用文档
文档目录13 节
  1. Key Capabilities
  2. Installation
  3. Quick Start
  4. Setting Up the Form Provider
  5. Using FormViewer (Read-Only)
  6. Using FormEditor (Editable)
  7. Using FormSections for Navigation
  8. Using FormFieldsValidation and FormDocumentValidation
  9. Component Map Types
  10. ViewerComponentMap
  11. EditorComponentMap
  12. Exported API
  13. Documentation

@bluprynt/forms-viewer

Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with @bluprynt/forms-core to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.

Key Capabilities

  • Read-only rendering — FormViewer renders a form from a definition and document using your custom view components, with automatic visibility and validation display.
  • Editable forms — FormEditor renders an editable form with per-field onChange handlers, array and array-of-rows item manipulation (add, remove, move), and live re-validation on every change.
  • Section navigation — FormSections enumerates visible top-level sections (including a synthetic root for ungrouped fields) and tracks the active section.
  • Validation display — FormFieldsValidation groups field-level errors by field; FormDocumentValidation renders document-level errors (schema mismatch, missing submittedAt, etc.).
  • Headless architecture — all rendering is delegated to component maps you provide (ViewerComponentMap, EditorComponentMap), so the package has zero UI opinions.

Installation

npm install @bluprynt/forms-viewer @bluprynt/forms-core ajv react react-dom

@bluprynt/forms-core, react, and react-dom are peer dependencies and must be installed in your project.

Quick Start

Setting Up the Form Provider

The Form component compiles the definition, computes visibility, runs validation, and exposes everything via context.

import type { FC } from 'react'
import { Form } from '@bluprynt/forms-viewer'
import type { FormDefinition, FormDocument } from '@bluprynt/forms-viewer'

const definition: FormDefinition = { /* ... */ }
const document: FormDocument = { /* ... */ }

const App: FC = () => {
  return (
    <Form definition={definition} data={document}>
      {/* FormViewer, FormEditor, FormSections, etc. */}
    </Form>
  )
}

Form props:

PropTypeDefaultDescription
definitionFormDefinition—The form schema
dataFormDocument—The form values document
sectionROOT | number—Active section id (use ROOT for ungrouped fields)
showInlineValidationbooleantrueWhether field components receive validation errors
childrenReactNode—Child components

Using FormViewer (Read-Only)

Use FormViewer when you only need to display submitted form values without editing. It renders each field through your component map in a read-only mode, applying visibility rules and showing validation state.

import type { FC } from 'react'
import { Form, FormViewer } from '@bluprynt/forms-viewer'
import type { ViewerComponentMap } from '@bluprynt/forms-viewer'

const components: ViewerComponentMap = {
  string: ({ field, value }) => <p>{field.label}: {value}</p>,
  number: ({ field, value }) => <p>{field.label}: {value}</p>,
  boolean: ({ field, value }) => <p>{field.label}: {value ? 'Yes' : 'No'}</p>,
  date: ({ field, value }) => <p>{field.label}: {value}</p>,
  select: ({ field, value, options }) => (
    <p>{field.label}: {options.find(o => o.value === value)?.label}</p>
  ),
  array: ({ field, children }) => <div>{field.label}: {children}</div>,
  file: ({ field, value }) => <p>{field.label}: {value?.name}</p>,
  section: ({ section, children }) => (
    <fieldset>
      <legend>{section.title}</legend>
      {children}
    </fieldset>
  ),
}

const ReadOnlyForm: FC = () => {
  return (
    <Form definition={definition} data={document}>
      <FormViewer components={components} />
    </Form>
  )
}

Using FormEditor (Editable)

Use FormEditor when users need to fill in or edit a form. It provides per-field onChange handlers and fires a callback on every change with the updated FormDocument JSON and current validation result.

import { useState, type FC } from 'react'
import { Form, FormEditor } from '@bluprynt/forms-viewer'
import type { EditorComponentMap, FormDocument, FormValidationResult } from '@bluprynt/forms-viewer'

const components: EditorComponentMap = {
  string: ({ field, value, onChange }) => (
    <input value={value ?? ''} onChange={e => onChange(e.target.value)} />
  ),
  number: ({ field, value, onChange }) => (
    <input type="number" value={value ?? ''} onChange={e => onChange(Number(e.target.value))} />
  ),
  boolean: ({ field, value, onChange }) => (
    <input type="checkbox" checked={value ?? false} onChange={e => onChange(e.target.checked)} />
  ),
  date: ({ field, value, onChange }) => (
    <input type="date" value={value ?? ''} onChange={e => onChange(e.target.value)} />
  ),
  select: ({ field, value, options, onChange }) => (
    <select value={value ?? ''} onChange={e => onChange(e.target.value)}>
      {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
    </select>
  ),
  array: ({ field, children, onAddItem }) => (
    <div>
      {children}
      <button onClick={onAddItem}>Add item</button>
    </div>
  ),
  file: ({ field, value, onChange }) => (
    <input type="file" onChange={e => { /* handle file */ }} />
  ),
  section: ({ section, children }) => (
    <fieldset>
      <legend>{section.title}</legend>
      {children}
    </fieldset>
  ),
}

const EditableForm: FC = () => {
  const [data, setData] = useState<FormDocument>(initialDocument)

  const handleChange = (doc: FormDocument, validation: FormValidationResult) => {
    setData(doc)
    // validation.valid, validation.fieldErrors, etc.
  }

  return (
    <Form definition={definition} data={data}>
      <FormEditor components={components} onChange={handleChange} />
    </Form>
  )
}

Using FormSections for Navigation

Use FormSections to render form sections as tabs, a sidebar menu, or any other navigation UI and let users switch between them. It enumerates visible top-level sections and tracks the active one.

import { useState, type FC } from 'react'
import { Form, FormViewer, FormSections, ROOT } from '@bluprynt/forms-viewer'

const FormWithSections: FC = () => {
  const [activeSection, setActiveSection] = useState<typeof ROOT | number>(ROOT)

  return (
    <Form definition={definition} data={document} section={activeSection}>
      <FormSections
        container={({ children }) => <nav>{children}</nav>}
        item={({ section, active, select }) => (
          <button onClick={select} style={{ fontWeight: active ? 'bold' : 'normal' }}>
            {section.title}
          </button>
        )}
        defaultSectionTitle="General"
        onSelect={setActiveSection}
      />
      <FormViewer components={viewerComponents} />
    </Form>
  )
}

Using FormFieldsValidation and FormDocumentValidation

Use FormDocumentValidation to display document-level errors — schema mismatch, invalid version, missing submittedAt, and similar structural issues. Use FormFieldsValidation to display field-level errors — values that don't match validation rules defined in the form (required, min/max, pattern, etc.).

import type { FC } from 'react'
import { Form, FormFieldsValidation, FormDocumentValidation } from '@bluprynt/forms-viewer'

const ValidationSummary: FC = () => {
  return (
    <Form definition={definition} data={document}>
      <FormDocumentValidation
        container={({ children }) => <div className="doc-errors">{children}</div>}
        error={({ code, message }) => <p>{message} ({code})</p>}
      />
      <FormFieldsValidation
        container={({ children }) => <div className="field-errors">{children}</div>}
        field={({ field, errors, children }) => (
          <div>
            <strong>{field?.label}</strong>
            {children}
          </div>
        )}
        error={({ message, rule }) => <p>{message} [{rule}]</p>}
      />
    </Form>
  )
}

Component Map Types

ViewerComponentMap

Component map for read-only rendering. Each key maps a field type to a React component.

KeyProps TypeDescription
stringStringViewPropsText field display
numberNumberViewPropsNumeric field display
booleanBooleanViewPropsBoolean field display
dateDateViewPropsDate field display
selectSelectViewPropsSelect field display (receives options)
arrayArrayViewPropsArray field display (receives children for items, itemDef)
array_obj?ArrayObjViewPropsArray-of-rows display. Receives itemsDef, the resolved kind ('list' | 'table') and children: ReactNode[][], indexed children[row][subField] and aligned with itemsDef.
fileFileViewPropsFile field display
sectionSectionViewPropsSection wrapper (receives children)
multiselect?MultiselectViewPropsMulti-select display. Value is (string | number)[]; receives options.
static?StaticViewPropsDisplay-only text block. Receives only field — no value, errors or suggestion.
blockchain?BlockchainViewPropsCAIP address display. Value is a string, stored verbatim.
sustainability?SustainabilityViewPropsSustainability references display. Value is { address, ccri?, cmc? }.
error?ErrorPropsOptional inline error renderer

All view field props extend BaseViewFieldProps which provides field: FieldContentItem and errors: FieldValidationError[]. StaticViewProps is the exception: it carries only field: StaticFieldContentItem, whose text is the content and whose label is an optional heading.

array_obj, multiselect, static, blockchain and sustainability are optional keys, so existing maps keep compiling. A field whose component is not supplied renders nothing rather than throwing.

EditorComponentMap

Component map for editable rendering. Extends view props with mutation callbacks.

KeyProps TypeDescription
stringStringEditPropsText input with onChange(value)
numberNumberEditPropsNumeric input with onChange(value)
booleanBooleanEditPropsBoolean input with onChange(value)
dateDateEditPropsDate input with onChange(value)
selectSelectEditPropsSelect input with onChange(value) and options
arrayArrayEditPropsArray editor with onAddItem, onRemoveItem(index), onMoveItem(from, to)
array_obj?ArrayObjEditPropsArray-of-rows editor with the same three row handlers. onAddItem appends an empty row; the per-cell onChange reaches each sub-field component.
fileFileEditPropsFile input with onChange(value)
sectionSectionEditPropsSection wrapper (receives children)
multiselect?MultiselectEditPropsCheckbox group. onChange((string | number)[] | undefined) — send the whole array.
static?StaticEditPropsDisplay-only text block. Identical to StaticViewProps; there is nothing to edit.
blockchain?BlockchainEditPropsText input with onChange(value). The CAIP format is never checked by the engine.
sustainability?SustainabilityEditPropsObject editor with onChange(value) — send the whole { address, ccri, cmc }. Emit undefined when every part is blank.
error?ErrorPropsOptional inline error renderer

All edit field props extend BaseEditFieldProps, which adds onChange(value) plus the optional onAcceptSuggestion() / onRejectSuggestion() handlers to the base view props. StaticEditProps does not — a static block has no onChange, so the same component serves both maps.

Every field component — read-only and editable — also receives the field's authoring metadata on field (description, placeholder, answer_guidelines, reference_id) and an optional suggestion ({ value, confidence, source }) when the document carries one for that field. Accepting copies the suggested value into the field's value and keeps the suggestion; rejecting removes the suggestion and leaves the value alone. See CHANGES.md.

Exported API

ExportKindDescription
FormComponentContext provider — compiles definition, computes visibility and validation
useFormContextHookAccess form context (definition, data, engine, visibility, validation)
FormViewerComponentRead-only form renderer
FormEditorComponentEditable form renderer with change callbacks
FormSectionsComponentSection navigation list
FormFieldsValidationComponentField-level validation error display
FormDocumentValidationComponentDocument-level validation error display
ROOTSymbolIdentifies the root (ungrouped fields) section
ViewerComponentMapTypeComponent map for FormViewer
EditorComponentMapTypeComponent map for FormEditor
BaseViewFieldPropsTypeBase props for view field components
BaseEditFieldPropsTypeBase props for edit field components
ErrorPropsTypeProps for inline error components
FormSectionEntryTypeSection entry in FormSections
FormSectionItemPropsTypeProps for section item renderer
FieldValidationFieldEntryTypeField + errors group in FormFieldsValidation
FormValuesEditorClassFluent editor for reading and writing form values against a definition
DocumentErrorClassError representing a document-level validation failure
FormDefinitionTypeJSON schema describing form structure, fields, sections, and rules
FormDocumentTypeJSON document containing user-submitted form values and optional suggestions
FieldSuggestionTypeA machine-proposed answer: { value, confidence, source }
FormSuggestionsTypeSparse map of suggestions keyed by stringified field id
FormValidationResultTypeValidation outcome with document-level and field-level errors
FieldTypeTypeUnion of supported field types (string, number, boolean, date, select, multiselect, array, array_obj, file, static, blockchain, sustainability)
FileValueTypeFile field value containing name, MIME type, size, and URL
SustainabilityValueTypeSustainability field value: { address, ccri?, cmc? }

Documentation

  • API Reference — detailed description of all exported components, hooks, and types
  • Architecture — internal design, data flow, and component structure
  • Development Guide — setup, testing, and contribution guidelines

版本与发布记录

@bluprynt/forms-viewer 共发布 6 个版本,首次发布于 2026/03/20;过去 12 个月发布了 6 个版本。

版本发布日期距今
4.2.0latest2026/10/2117 天前
4.1.02026/09/221 个月前
4.0.12026/06/294 个月前
3.0.02026/03/247 个月前
2.0.02026/03/247 个月前
1.0.02026/03/207 个月前

关于 @bluprynt/forms-viewer 的常见问题

@bluprynt/forms-viewer 是什么?

Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with @bluprynt/forms-core to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.

如何安装 @bluprynt/forms-viewer?

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

@bluprynt/forms-viewer 支持 TypeScript 吗?

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

@bluprynt/forms-viewer 支持 ESM 还是 CommonJS?

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

@bluprynt/forms-viewer 可以商用吗?

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

@bluprynt/forms-viewer 的下载量有多少?

根据 npm 官方下载统计,@bluprynt/forms-viewer 在 2026/10/09 – 2026/11/07 这 30 天内被下载 20,803 次,日均约 693 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bluprynt/forms-viewer 还在维护吗?

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