---
title: "Questionnaire"
description: "Tek tek gösterilen sorulardan oluşan çok adımlı form: tek ve çoklu seçim, serbest metin, atlama, doğrulama ve ilerleme."
---

<Callout type="info" title="Ne zaman kullanılır">
İlk kurulum anketi, geri bildirim, uygun planı bulma gibi sıralı sorular. Soruları ve cevapları bileşen yönetir; kapatma, kaydetme ve dallanma uygulamanızda kalır.
</Callout>

## Kurulum

```bash
npx shadcn@latest add @ikas/questionnaire
```

Registry tanımı yoksa önce [Kurulum](https://builders.ikas.com/tr/docs/app-development/ui-kit/installation) adımlarını tamamlayın. shadcn/ui Questionnaire ile aynı parçaları ve prop'ları kullanır, ama ek paket gerektirmez; her `tsconfig` ayarında çalışır. Metinler Türkçedir: “Soru 1 / 3”, Geri, Atla, İleri, Gönder.

## Örnekler

### İlk kurulum anketi

Questionnaire'e items verin (name, required, choices). multiple çoklu seçim açar, QuestionnaireInput serbest metin ekler. required olmayan sorularda Atla görünür. Cevaplar onSubmit'te FormData ile okunur.

**Örnek: İlk kurulum anketi** (`questionnaire/onboarding`) · [Canlı önizleme](https://builders.ikas.com/ui-preview/demo/questionnaire/onboarding)

```tsx
import * as React from "react"
import { CheckCircle2Icon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Questionnaire,
  QuestionnaireActions,
  QuestionnaireChoice,
  QuestionnaireChoiceDescription,
  QuestionnaireChoices,
  QuestionnaireDescription,
  QuestionnaireError,
  QuestionnaireInput,
  QuestionnaireItem,
  QuestionnaireNext,
  QuestionnairePrevious,
  QuestionnaireProgress,
  QuestionnaireSkip,
  QuestionnaireSubmit,
  QuestionnaireTitle,
} from "@/components/ui/questionnaire"

type Item = {
  name: string
  prompt: string
  description?: string
  required?: boolean
  multiple?: boolean
  choices: { value: string; label: string; description?: string }[]
  input?: { label: string; placeholder: string }
}

const items: Item[] = [
  {
    name: "size",
    required: true,
    prompt: "Mağazanızda kaç ürün var?",
    choices: [
      { value: "small", label: "100'den az" },
      { value: "medium", label: "100 – 1.000" },
      { value: "large", label: "1.000'den fazla", description: "Toplu içe aktarma önerilir." },
    ],
  },
  {
    name: "channels",
    required: true,
    multiple: true,
    prompt: "Hangi kanallarda satış yapıyorsunuz?",
    description: "Birden fazla seçebilirsiniz.",
    choices: [
      { value: "web", label: "Online mağaza" },
      { value: "marketplace", label: "Pazaryeri" },
      { value: "social", label: "Sosyal medya" },
      { value: "store", label: "Fiziksel mağaza" },
    ],
  },
  {
    name: "source",
    prompt: "Uygulamayı nereden duydunuz?",
    description: "İsteğe bağlı.",
    choices: [
      { value: "store", label: "Uygulama mağazası" },
      { value: "friend", label: "Tavsiye" },
    ],
    input: { label: "Diğer", placeholder: "Başka bir kaynak" },
  },
]

/** First-run setup survey: required single and multiple choice, then an optional item. */
export default function QuestionnaireOnboarding() {
  const [done, setDone] = React.useState(false)

  if (done) {
    return (
      <div className="flex w-full max-w-md flex-col items-center gap-3 py-10 text-center">
        <CheckCircle2Icon className="size-8 text-success" />
        <p className="font-medium">Kurulum tercihleri kaydedildi</p>
        <Button variant="outline" size="sm" onClick={() => setDone(false)}>
          Yeniden başlat
        </Button>
      </div>
    )
  }

  return (
    <Questionnaire
      className="max-w-md"
      items={items.map(({ name, required, choices }) => ({ name, required, choices }))}
      onSubmit={(event) => {
        event.preventDefault()
        setDone(true)
      }}
    >
      <QuestionnaireProgress />
      {items.map((item) => (
        <QuestionnaireItem
          key={item.name}
          name={item.name}
          required={item.required}
          multiple={item.multiple}
        >
          <QuestionnaireTitle>{item.prompt}</QuestionnaireTitle>
          {item.description && <QuestionnaireDescription>{item.description}</QuestionnaireDescription>}
          <QuestionnaireChoices>
            {item.choices.map((choice) => (
              <QuestionnaireChoice key={choice.value} value={choice.value}>
                {choice.label}
                {choice.description && <QuestionnaireChoiceDescription>{choice.description}</QuestionnaireChoiceDescription>}
              </QuestionnaireChoice>
            ))}
            {item.input && <QuestionnaireInput aria-label={item.input.label} placeholder={item.input.placeholder} />}
          </QuestionnaireChoices>
          <QuestionnaireError />
        </QuestionnaireItem>
      ))}
      <QuestionnaireActions>
        <QuestionnairePrevious />
        <QuestionnaireSkip />
        <QuestionnaireNext />
        <QuestionnaireSubmit />
      </QuestionnaireActions>
    </Questionnaire>
  )
}
```

### Kart içinde ve kısayollar

shortcuts="letters" seçeneklere A, B, C tuşlarını atar; Enter sonraki soruya geçer. QuestionnaireProgress label ile ilerleme metnini değiştirin.

**Örnek: Kart içinde** (`questionnaire/card`) · [Canlı önizleme](https://builders.ikas.com/ui-preview/demo/questionnaire/card)

```tsx
import { toast } from "sonner"

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import {
  Questionnaire,
  QuestionnaireActions,
  QuestionnaireChoice,
  QuestionnaireChoices,
  QuestionnaireError,
  QuestionnaireItem,
  QuestionnaireNext,
  QuestionnairePrevious,
  QuestionnaireProgress,
  QuestionnaireSubmit,
  QuestionnaireTitle,
} from "@/components/ui/questionnaire"

const items = [
  {
    name: "ease",
    prompt: "Kurulum ne kadar kolaydı?",
    choices: ["Çok kolay", "Kolay", "Zor"],
  },
  {
    name: "missing",
    prompt: "En çok hangi özelliği istersiniz?",
    choices: ["Toplu düzenleme", "Otomatik raporlar", "Daha fazla entegrasyon"],
  },
]

/** Short feedback survey in a card. Letter keys pick an answer, Enter moves on. */
export default function QuestionnaireCard() {
  return (
    <Card className="w-full max-w-md">
      <CardHeader>
        <CardTitle>Görüşünüz bizim için önemli</CardTitle>
        <CardDescription>İki soru, 30 saniye.</CardDescription>
      </CardHeader>
      <CardContent>
        <Questionnaire
          shortcuts="letters"
          items={items.map((item) => ({ name: item.name, required: true, choices: item.choices.map((value) => ({ value })) }))}
          onSubmit={(event) => {
            event.preventDefault()
            toast.success("Teşekkürler, yanıtınız kaydedildi")
            event.currentTarget.reset()
          }}
        >
          <QuestionnaireProgress label={(current, total) => `${current}/${total}`} />
          {items.map((item) => (
            <QuestionnaireItem key={item.name} name={item.name} required>
              <QuestionnaireTitle>{item.prompt}</QuestionnaireTitle>
              <QuestionnaireChoices>
                {item.choices.map((choice) => (
                  <QuestionnaireChoice key={choice} value={choice}>
                    {choice}
                  </QuestionnaireChoice>
                ))}
              </QuestionnaireChoices>
              <QuestionnaireError />
            </QuestionnaireItem>
          ))}
          <QuestionnaireActions>
            <QuestionnairePrevious />
            <QuestionnaireNext />
            <QuestionnaireSubmit />
          </QuestionnaireActions>
        </Questionnaire>
      </CardContent>
    </Card>
  )
}
```

## Kullanım ilkeleri

**Yapın:**

- Her soruyu tek bir şey sorar halde tutun.
- Gerekmeyen soruları required yapmayın; kullanıcı atlayabilsin.
- Gönderince sonucu gösterin veya akışı kapatın.

**Yapmayın:**

- Ondan fazla soru sormayın.
- Questionnaire'i bir form alanı gibi sayfanın ortasına gömüp başka alanlarla karıştırmayın.

## API

Parçalar: `Questionnaire`, `QuestionnaireProgress`, `QuestionnaireItem`, `QuestionnaireTitle`, `QuestionnaireDescription`, `QuestionnaireChoices`, `QuestionnaireChoice`, `QuestionnaireChoiceDescription`, `QuestionnaireInput`, `QuestionnaireError`, `QuestionnaireActions` ve gezinme butonları. Klavye: Enter sonraki soruya geçer, Cmd/Ctrl+Enter her yerden ilerler, sol ve sağ ok önceki ve sonraki soruya gider.

### `Questionnaire`

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `items` | `readonly QuestionnaireItemDefinition[]` | - | Soru sırası ve ayarları { name, required?, disabled?, choices? }. Verilmezse sayfadaki sıra kullanılır. |
| `defaultItem` | `string` | - | Kontrolsüz kullanımda ilk gösterilen soru. |
| `item` | `string` | - | Kontrollü kullanımda aktif soru. |
| `onItemChange` | `(item: string) => void` | - | Aktif soru değişince yeni sorunun adıyla çağrılır. |
| `shortcuts` | `QuestionnaireShortcuts` | - | letters veya numbers: seçenekleri harf ya da rakam tuşuyla seçtirir. |

### `QuestionnaireItem`

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `name` (zorunlu) | `string` | - | Cevapların FormData'daki alan adı. |
| `required` | `boolean` | `false` | Cevap verilmeden İleri'ye izin vermez, Atla'yı gizler. |
| `multiple` | `boolean` | `false` | Radyo yerine onay kutuları. |
| `invalid` | `boolean` | `false` | Hata durumunu zorlar, örn. kendi şema doğrulamanızdan. |
| `onStatusChange` | `(status: QuestionnaireStatus) => void` | - | Soru cevapsız, cevaplanmış veya atlanmış olunca çağrılır. |

### `QuestionnaireChoice`

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `value` (zorunlu) | `string` | - | Gönderilen değer. |
| `defaultChecked` | `boolean` | `false` | Başlangıçta ve sıfırlamada seçili. |
| `disabled` | `boolean` | `false` |  |
| `onChange` | `React.ChangeEventHandler<HTMLInputElement>` | - | Yerel radyo veya onay kutusunun change olayı. |

### `QuestionnaireProgress`

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `label` | `(current: number, total: number) => React.ReactNode` | `` (current, total) => `Soru ${current} / ${total}` `` | Çubuğun yanındaki metin. (mevcut, toplam) alır; varsayılan “Soru 1 / 3”. |

### `QuestionnaireNext`

Geri, Atla ve Gönder de aynı prop'ları alır.

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `size` | `ButtonProps["size"]` | - |  |
| `variant` | `ButtonVariant` | `"solid"` | Button variant'ı. İleri ve Gönder solid, Atla outline, Geri ghost. |
| `color` | `ButtonColor` | - |  |
| `asChild` | `boolean` | - | Buton yerine alt öğeyi render eder (Radix gibi). |
