@letar/forms

Conversational Mode

Typeform-style one-question-at-a-time form experience with animations

Full example

The complete sandbox example, read directly from the form-develop-app source at build time — switch framework/skin to see ConversationalMode wired to a real form. No shadcn/Vue/Angular equivalent exists yet — those tabs show as disabled.

apps/form-develop-app/src/app/conversational-demo/page.tsx
'use client'

import { Box, Heading, Text, VStack } from '@chakra-ui/react'
import { ConversationalMode, Form } from '@letar/forms'
import { useState } from 'react'
import { DemoPageLayout } from '../_components'

export default function ConversationalDemoPage() {
  const [submittedData, setSubmittedData] = useState<Record<string, unknown> | null>(null)

  return (
    <DemoPageLayout title="Conversational Mode" description="Typeform-стиль: одно поле за раз с анимацией и навигацией">
      <VStack gap={8} align="stretch">
        <Box maxW="lg" mx="auto" w="full">
          <Form
            debug
            initialValue={{
              name: '',
              email: '',
              experience: undefined,
              recommend: undefined,
              feedback: '',
            }}
            onSubmit={(data) =>
              setSubmittedData(data as Record<string, unknown>)}
          >
            <ConversationalMode
              showProgress
              showQuestionNumber
              completedScreen={
                <VStack gap={2} textAlign="center">
                  <Text fontSize="2xl">Спасибо за ответы!</Text>
                  <Form.Button.Submit>Отправить результаты</Form.Button.Submit>
                </VStack>
              }
            >
              <Form.Field.String name="name" label="Как вас зовут?" placeholder="Введите имя" />
              <Form.Field.String name="email" label="Ваш email?" placeholder="email@example.com" />
              <Form.Field.Likert
                name="experience"
                label="Как вы оцениваете наш продукт?"
                anchors={['Ужасно', 'Плохо', 'Нормально', 'Хорошо', 'Отлично']}
                showNumbers
              />
              <Form.Field.YesNo
                name="recommend"
                label="Порекомендуете ли вы нас друзьям?"
                yesLabel="Да, конечно!"
                noLabel="Нет"
                variant="thumbs"
              />
              <Form.Field.Textarea name="feedback" label="Что мы можем улучшить?" placeholder="Ваши идеи..." />
            </ConversationalMode>
          </Form>
        </Box>

        {submittedData && (
          <Box p={4} bg="bg.subtle" borderRadius="md">
            <Heading size="sm" mb={2}>
              Отправленные данные:
            </Heading>
            <pre style={{ fontSize: '12px', overflow: 'auto' }}>{JSON.stringify(submittedData, null, 2)}</pre>
          </Box>
        )}
      </VStack>
    </DemoPageLayout>
  )
}

Overview

Conversational Mode shows one field at a time with smooth animations, a progress bar, and keyboard-first navigation. Ideal for surveys, onboarding, and marketing forms where higher completion rates matter.

Basic Usage

<Form initialValue={data} onSubmit={handleSubmit}>
  <ConversationalMode showProgress showQuestionNumber>
    <Form.Field.String name="name" label="What's your name?" />
    <Form.Field.String name="email" label="Your email?" />
    <Form.Field.YesNo name="subscribe" label="Subscribe to updates?" />
  </ConversationalMode>
</Form>

Each child element becomes one step. The user sees one field at a time and navigates with Enter or buttons.

Props

PropTypeDefaultDescription
showProgressbooleantrueShow progress bar
showQuestionNumberbooleantrueShow "Question 3 of 7"
nextLabelstring'Далее'Next button text
prevLabelstring'Назад'Previous button text
submitLabelstring'Отправить'Submit button text (last step)
welcomeScreenReactNodeContent before first question
completedScreenReactNodeContent after last question
onComplete() => voidCalled when all questions answered

Keyboard Navigation

KeyAction
EnterNext question
Alt + Arrow DownNext question
Alt + Arrow UpPrevious question

Custom Hook

For building your own conversational UI:

import { useConversationalState } from '@letar/forms'

const state = useConversationalState(5) // 5 fields
state.currentIndex // 0
state.progress // 0.2
state.next() // go to next
state.prev() // go to previous
state.isCompleted // false

Live Example

Try the interactive example on forms-example.letar.best.

On this page