Zoeken...  ⌘K GitHub

FormSurvey Forms

Klanttevredenheidsformulier met 1-10 schaal, meerkeuzevragen en open tekstvelden.

/form-survey
src/components/forms/FormSurvey.astro
---
/**
 * FormSurvey — klanttevredenheidsformulier: 1-10 schaal, meerkeuze en open velden.
 *
 * Props:
 * - heading?: string
 * - sub?: string
 * - scaleQuestion?: string
 * - scaleLow?: string
 * - scaleHigh?: string
 * - communicationOptions?: string[]
 * - recommendQuestion?: string
 * - recommendOptions?: string[]
 * - submitLabel?: string
 */
interface Props {
  heading?: string;
  sub?: string;
  scaleQuestion?: string;
  scaleLow?: string;
  scaleHigh?: string;
  communicationOptions?: string[];
  recommendQuestion?: string;
  recommendOptions?: string[];
  submitLabel?: string;
}
const {
  heading = 'Klantfeedback formulier',
  sub = 'Je feedback helpt ons om onze dienstverlening continu te verbeteren. Invullen duurt minder dan 2 minuten.',
  scaleQuestion = 'Hoe tevreden ben je over onze samenwerking?',
  scaleLow = 'Heel ontevreden',
  scaleHigh = 'Heel tevreden',
  communicationOptions = ['Uitstekend', 'Goed', 'Voldoende', 'Matig', 'Slecht'],
  recommendQuestion = 'Zou je ons aanbevelen aan anderen?',
  recommendOptions = ['Zeker wel', 'Waarschijnlijk wel', 'Misschien', 'Waarschijnlijk niet'],
  submitLabel = 'Feedback versturen',
} = Astro.props;
const scale = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
---

<section class="bl-section fsv">
  <div class="bl-inner bl-inner--narrow fsv-inner">
    <div class="fsv-header">
      <h2 class="fsv-heading">{heading}</h2>
      <p class="fsv-subtext">{sub}</p>
    </div>
    <form class="fsv-form" novalidate>
      <fieldset class="fsv-fieldset">
        <legend class="fsv-legend">{scaleQuestion}</legend>
        <div class="fsv-scale">
          {scale.map((n) => (
            <label class="fsv-scale-item">
              <input class="fsv-scale-input" type="radio" name="overall_score" value={String(n)} required />
              <span class="fsv-scale-num">{n}</span>
            </label>
          ))}
        </div>
        <div class="fsv-scale-labels"><span>{scaleLow}</span><span>{scaleHigh}</span></div>
      </fieldset>
      <fieldset class="fsv-fieldset">
        <legend class="fsv-legend">Hoe beoordeel je de communicatie?</legend>
        <div class="fsv-radios">
          {communicationOptions.map((o) => (
            <label class="fsv-radio-item"><input class="fsv-radio" type="radio" name="communication" value={o} required /> {o}</label>
          ))}
        </div>
      </fieldset>
      <div class="fsv-field">
        <label class="fsv-label" for="fsv-best">Wat gaat er goed?</label>
        <textarea class="fsv-textarea" id="fsv-best" name="positive" rows="3" placeholder="Bijv. snelle responstijden, goede rapportages..."></textarea>
      </div>
      <div class="fsv-field">
        <label class="fsv-label" for="fsv-improve">Wat kan er beter?</label>
        <textarea class="fsv-textarea" id="fsv-improve" name="improvement" rows="3" placeholder="Wees gerust eerlijk, we leren graag van je feedback."></textarea>
      </div>
      <fieldset class="fsv-fieldset">
        <legend class="fsv-legend">{recommendQuestion}</legend>
        <div class="fsv-radios fsv-radios--inline">
          {recommendOptions.map((o) => (
            <label class="fsv-radio-item"><input class="fsv-radio" type="radio" name="recommend" value={o} required /> {o}</label>
          ))}
        </div>
      </fieldset>
      <div class="fsv-field">
        <label class="fsv-label" for="fsv-name">Naam (optioneel)</label>
        <input class="fsv-input" type="text" id="fsv-name" name="name" placeholder="Jouw naam" autocomplete="name" />
      </div>
      <button class="fsv-submit" type="submit">{submitLabel}</button>
    </form>
  </div>
</section>

<style>
.fsv-header{margin-bottom:2rem}
.fsv-heading{font-size:1.75rem;font-weight:800;color:var(--color-primary, #0a0a0a);margin:0 0 .5rem}
.fsv-subtext{font-size:1rem;color:#555;margin:0;line-height:1.6}
.fsv-form{display:flex;flex-direction:column;gap:1.75rem}
.fsv-fieldset{border:none;padding:0;margin:0}
.fsv-legend{font-size:1.05rem;font-weight:700;color:var(--color-primary, #0a0a0a);margin-bottom:1rem}
.fsv-scale{display:flex;gap:.4rem;flex-wrap:wrap}
.fsv-scale-item{cursor:pointer}
.fsv-scale-input{display:none}
.fsv-scale-num{display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:8px;background:#f5f5f5;font-size:.9375rem;font-weight:600;color:#374151;border:1.5px solid transparent;transition:border-color .15s,background-color .15s,color .15s}
.fsv-scale-input:checked+.fsv-scale-num{background:var(--color-accent, #6366f1);color:#fff;border-color:var(--color-accent, #6366f1)}
.fsv-scale-labels{display:flex;justify-content:space-between;font-size:.8125rem;color:#555;margin-top:.5rem}
.fsv-radios{display:flex;flex-direction:column;gap:.5rem}
.fsv-radios--inline{flex-direction:row;flex-wrap:wrap;gap:.5rem}
.fsv-radio-item{display:flex;align-items:center;gap:.5rem;font-size:1rem;color:#374151;cursor:pointer;padding:.55rem 1rem;background:#f9f9f9;border-radius:8px;border:1.5px solid transparent}
.fsv-radio-item:has(input:checked){border-color:var(--color-accent, #6366f1);background:#eef2ff;color:var(--color-accent, #6366f1)}
.fsv-radio{accent-color:var(--color-accent, #6366f1)}
.fsv-field{display:flex;flex-direction:column;gap:.4rem}
.fsv-label{font-size:.95rem;font-weight:600;color:var(--color-primary, #0a0a0a)}
.fsv-input,.fsv-textarea{padding:.7rem .9rem;border:1.5px solid #ddd;border-radius:8px;font-size:1rem;color:var(--color-primary, #0a0a0a);background:#fff;transition:border-color .2s;font-family:inherit;box-sizing:border-box;width:100%}
.fsv-input:focus,.fsv-textarea:focus{outline:none;border-color:var(--color-accent, #6366f1);box-shadow:0 0 0 3px #6366f11f}
.fsv-textarea{resize:vertical;min-height:90px}
.fsv-submit{padding:.9rem 2rem;background:var(--color-accent, #6366f1);color:#fff;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;transition:opacity .2s;align-self:flex-start}
.fsv-submit:hover{opacity:.88}
</style>

Props

Prop Type Default Beschrijving
heading string 'Klantfeedback formulier' Kop boven het formulier
sub string - Toelichtende tekst onder de kop
scaleQuestion string - Vraag boven de 1-10 schaal
scaleLow string - Label aan de lage kant van de schaal
scaleHigh string - Label aan de hoge kant van de schaal
communicationOptions string[] - Antwoordopties communicatie-vraag
recommendQuestion string - Aanbevelings-vraag
recommendOptions string[] - Antwoordopties aanbevelings-vraag
submitLabel string 'Feedback versturen' Tekst op de submit-knop

* = verplicht