Docs
v1.4.1
GitHubSite
Pro / Response viewer

Response viewer

Browse, search, filter, and export form responses with table, card, detail, and timeline views. Part of the Pro commercial package.

What it does

ResponseViewer is a React component that displays form submissions in four view modes. Pass it a schema and an array of FormResponse objects, and it renders an interactive viewer with search, filter, export, and statistics.

The ResponseViewer is part of @squaredr/fieldcraft-pro, which requires a commercial licence.

Auto-inherit from host page

The component inherits CSS custom properties from your host page automatically. No theme prop is needed for basic usage — it matches your app's look and feel out of the box.

import { ResponseViewer } from '@squaredr/fieldcraft-pro'
import type { FormEngineSchema, FormResponse } from '@squaredr/fieldcraft-core'

type Props = {
  schema: FormEngineSchema
  responses: FormResponse[]
}

export default function ResponsesPage({ schema, responses }: Props) {
  return (
    <ResponseViewer
      schema={schema}
      responses={responses}
    />
  )
}

View modes

Users toggle between modes using the view-mode switcher in the toolbar.

ModeDescription
TableSpreadsheet-style table with sortable columns, pagination, and search. Default view.
CardCard grid showing a summary of each response. Good for visual scanning.
DetailFull single-response view with all field values displayed in order.
TimelineChronological timeline of responses with timestamps.

Features

FeatureDescription
SearchFull-text search across all response values.
FilterFilter by date range and field values.
CSV/JSON exportExport all or selected responses.
Statistics dashboardSummary stats and charts for numeric and choice fields.
Bulk operationsSelect multiple responses for delete or export.
Custom field renderersOverride how specific field types display in the viewer.
Column label customizationOverride CSV/table column headers per question.
Configurable page size10, 25, 50, or 100 responses per page.

Props

Required

PropTypeDescription
schemaFormEngineSchemaThe form schema. Used to determine field types, labels, and structure.
responsesFormResponse[]Array of form responses to display.

Callbacks

PropTypeDescription
onResponseSelect(response: FormResponse) => voidCalled when a response row or card is clicked.
onExport(format: "csv" | "json", count: number) => voidCalled after CSV or JSON export completes.
onDelete(sessionToken: string) => voidCalled when a single response is deleted. Provide this to enable the delete UI.
onBulkDelete(sessionTokens: string[]) => voidCalled when multiple responses are bulk-deleted.
onBulkExport(responses: FormResponse[]) => voidCalled when selected responses are bulk-exported.

Display

PropTypeDefaultDescription
heightstring | numberContainer height.
widthstring | numberContainer width.
pageSize10 | 25 | 50 | 10025Responses per page.
selectablebooleanEnable checkbox selection for bulk operations.

Customization

PropTypeDefaultDescription
fieldRenderersRecord<string, FieldRenderer>Custom per-type field renderers. Keys are field type strings.
filenamestring"responses"Base filename for CSV/JSON downloads.
dateFormat"locale" | "iso""locale"Date format for export. "locale" uses toLocaleString(), "iso" uses toISOString().
columnLabelsRecord<string, string>Override column headers. Maps question ID to display label.

Custom field renderers

Override how specific field types are rendered in the viewer by passing a fieldRenderers map. Each renderer receives the field data and the full response:

import { ResponseViewer } from '@squaredr/fieldcraft-pro'

const customRenderers = {
  rating: (field) => (
    <span>{''.repeat(field.value as number)}</span>
  ),
  color: (field) => (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
      <span style={{
        width: 16, height: 16, borderRadius: 4,
        background: field.value as string,
      }} />
      {field.value as string}
    </span>
  ),
}

<ResponseViewer
  schema={schema}
  responses={responses}
  fieldRenderers={customRenderers}
/>

Handling delete and export

Provide callback props to wire up delete and export to your API:

<ResponseViewer
  schema={schema}
  responses={responses}
  selectable
  onDelete={async (sessionToken) => {
    await fetch(`/api/responses/${sessionToken}`, { method: 'DELETE' })
    // Re-fetch responses after deletion
  }}
  onBulkDelete={async (sessionTokens) => {
    await fetch('/api/responses/bulk-delete', {
      method: 'POST',
      body: JSON.stringify({ sessionTokens }),
    })
  }}
  onExport={(format, count) => {
    console.log(`Exported ${count} responses as ${format}`)
  }}
/>

The delete UI only appears when onDelete is provided. Bulk operations require both selectable and the relevant bulk callback (onBulkDelete or onBulkExport).

Next steps

On this page