Vai al contenuto
animorio
EN
Tutti i componenti

I passi della prenotazione

Passi, Transizioni, SVGGSAPImpegnativaPeso compresso: Demo 10 KBGSAP 28 KBGratisScarica lo zip

Una prenotazione in quattro passi uniti da una linea che si riempie: il passo fatto si colora dal centro mentre l’icona gira via e al suo posto si disegna una spunta, il pannello esce da un lato ed entra il successivo mentre la scheda prende la nuova altezza; alla fine un anello e una spunta si disegnano e i passi fanno un’onda.

Il codice

Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nelle schede React e Vue la stessa demo è già un componente, che spegne le sue animazioni quando esce dalla pagina.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The booking steps</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/red-hat-display@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the booking steps: four steps joined by a line that fills as they are done; each step done turns its icon
         into a tick, and the panels under them slide one into the other while the card takes their height -->
    <div class="book" data-book data-autoclic>
      <div class="steps">
        <span class="steps__track" aria-hidden="true"><span class="steps__fill" data-fill></span></span>
        <ol class="steps__list" data-steps>
          <li class="step">
            <button class="step__node" type="button" aria-label="Dates">
              <span class="step__disc"></span>
              <svg class="step__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 7.5c0-1.1.9-2 2-2h10a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2zM5 10h14M9 3.5v4M15 3.5v4"/></svg>
              <svg class="step__tick" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.5 12.5l3.8 3.8 7.2-8"/></svg>
            </button>
            <span class="step__label">Dates</span>
          </li>
          <li class="step">
            <button class="step__node" type="button" aria-label="Room">
              <span class="step__disc"></span>
              <svg class="step__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3.5 18.5V7M3.5 13h17v5.5M20.5 13v-1.5a3 3 0 0 0-3-3h-6v4.5M6 12.2a2 2 0 1 0 0-.01"/></svg>
              <svg class="step__tick" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.5 12.5l3.8 3.8 7.2-8"/></svg>
            </button>
            <span class="step__label">Room</span>
          </li>
          <li class="step">
            <button class="step__node" type="button" aria-label="Details">
              <span class="step__disc"></span>
              <svg class="step__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 12a3.6 3.6 0 1 0 0-7.2 3.6 3.6 0 0 0 0 7.2zM5 19.5c.8-3.2 3.6-5 7-5s6.2 1.8 7 5"/></svg>
              <svg class="step__tick" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.5 12.5l3.8 3.8 7.2-8"/></svg>
            </button>
            <span class="step__label">Details</span>
          </li>
          <li class="step">
            <button class="step__node" type="button" aria-label="Confirm">
              <span class="step__disc"></span>
              <svg class="step__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 3.5h7.5L19 8v11a1.5 1.5 0 0 1-1.5 1.5h-10A1.5 1.5 0 0 1 6 19V5a1.5 1.5 0 0 1 1-1.5zM14 3.5V8h5M9.5 13h5M9.5 16.5h3"/></svg>
              <svg class="step__tick" viewBox="0 0 24 24" aria-hidden="true"><path d="M6.5 12.5l3.8 3.8 7.2-8"/></svg>
            </button>
            <span class="step__label">Confirm</span>
          </li>
        </ol>
      </div>

      <form class="book__form" novalidate data-form>
        <div class="book__panels" data-panels>
          <section class="panel" aria-labelledby="h-dates" data-panel>
            <h2 class="panel__title" id="h-dates" tabindex="-1">When are you coming?</h2>
            <fieldset class="group">
              <legend class="group__label">Arrival in June</legend>
              <div class="chips" data-chips="day"></div>
            </fieldset>
            <fieldset class="group">
              <legend class="group__label">How long</legend>
              <div class="chips" data-chips="stay"></div>
            </fieldset>
          </section>

          <section class="panel" aria-labelledby="h-room" hidden data-panel>
            <h2 class="panel__title" id="h-room" tabindex="-1">Choose a room</h2>
            <div class="rooms" role="radiogroup" aria-labelledby="h-room" data-rooms></div>
          </section>

          <section class="panel" aria-labelledby="h-details" hidden data-panel>
            <h2 class="panel__title" id="h-details" tabindex="-1">Who is coming?</h2>
            <label class="field">
              <span class="field__label">Your name</span>
              <input class="field__input" name="name" autocomplete="name" data-name>
              <span class="field__error" aria-live="polite" data-error></span>
            </label>
            <label class="field">
              <span class="field__label">Email</span>
              <input class="field__input" name="email" type="email" autocomplete="email" inputmode="email" data-email>
              <span class="field__error" aria-live="polite" data-error></span>
            </label>
          </section>

          <section class="panel" aria-labelledby="h-confirm" hidden data-panel>
            <h2 class="panel__title" id="h-confirm" tabindex="-1">All looks right?</h2>
            <dl class="summary" data-summary></dl>
            <div class="total"><span>Total</span><strong data-total>€0</strong></div>
          </section>

          <section class="panel panel--done" aria-labelledby="h-done" hidden data-panel>
            <svg class="done__mark" viewBox="0 0 80 80" aria-hidden="true"><circle cx="40" cy="40" r="34" data-ring/><path d="M26 41.5l9.5 9.5L55 31" data-check/></svg>
            <h2 class="panel__title" id="h-done" tabindex="-1">You’re booked</h2>
            <p class="done__text" data-done-text></p>
            <button class="btn btn--ghost" type="button" data-again>Make another booking</button>
          </section>
        </div>

        <div class="book__actions" data-actions>
          <button class="btn btn--ghost" type="button" data-back>Back</button>
          <button class="btn btn--main" type="submit" data-next>
            <span class="btn__clip"><span class="btn__label" data-next-label>Continue</span></span>
            <svg class="btn__arrow" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h13M13 6.5l5.5 5.5-5.5 5.5"/></svg>
            <svg class="btn__spin" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8"/></svg>
          </button>
        </div>
      </form>
    </div>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Cambia valori, colori e testi con le manopole e guarda l’animazione rispondere dal vivo. Oppure scrivi tu nel codice. Poi scarica la cartella con le tue modifiche.

39 valori da cambiare

Oppure chiedila a Claude Code

Col connettore di Animorio, Claude Code la prende da qui con tutta la sua guida e la adatta al tuo progetto. Incolla questa richiesta:

Prendi «I passi della prenotazione» da Animorio e adattala al mio sito

Cosa fa

Su un fondo nero quattro passi tondi con le loro icone (un calendario, un letto, una persona, un foglio) uniti da una linea grigia, coi nomi Dates, Room, Details e Confirm; sotto, una scheda scura con When are you coming?, i chip del giorno d’arrivo a giugno (Fri 12, Sat 13, Sun 14, Mon 15) e della durata (Two nights, Three nights, A week), quelli scelti color miele, e un pulsante miele Continue con la freccia. Scegliendo un chip, il miele lo riempie partendo dal punto premuto. Andando avanti, la linea si riempie fino al passo dopo, il passo fatto si riempie di miele dal centro mentre la sua icona gira via e al suo posto si disegna una spunta, e il passo raggiunto fa un balzo; il pannello esce a sinistra ed entra il successivo da destra con le righe che salgono una dopo l’altra, mentre la scheda prende la sua altezza. Nella stanza tre camere col prezzo: scegliendone una, la cornice diventa miele e la spunta salta fuori. Nei dati nome e email: lasciati vuoti o con un’email a metà, il campo diventa rosso, trema e sotto compare il perché. Nell’ultimo sguardo il riepilogo con arrivo, partenza, camera, ospite ed email e un totale che conta da zero; il pulsante diventa Confirm booking, con le parole che scorrono e la larghezza che cambia. Confermando, nel pulsante gira un arco con Booking, poi anche l’ultimo passo si spunta, il pannello diventa You’re booked con un anello e una spunta che si disegnano, una riga con l’email e il giorno, e i quattro passi fanno un’onda; Make another booking ricomincia. Un passo fatto si clicca per tornarci, Back torna indietro di uno.

Come funziona

La linea e i passi

La linea fra il centro del primo e dell’ultimo passo è una barra scalata con scaleX alla frazione del passo in FILL secondi (power3.inOut). Ogni passo ha un disco miele, la sua icona e una spunta: fatto, il disco cresce dal centro con back.out, l’icona gira e si rimpicciolisce, la spunta si disegna con stroke-dashoffset; il passo raggiunto balza con elastic.out quando arriva la linea (all’80 per cento di FILL). Tornando indietro, i passi si disfano da destra.

I pannelli che si incrociano

Il pannello che esce si toglie dal flusso (position absolute, dov’era), così la scheda può misurare l’altezza con quello nuovo; poi in MOVE secondi la scheda passa dalla vecchia altezza alla nuova, il vecchio pannello scivola via di SLIDE pixel sfumando, il nuovo entra dall’altro lato con le righe che salgono una dopo l’altra. Intanto la scheda taglia quello che le passa oltre il bordo.

I tasti della scheda

I chip sono pulsanti radio: il miele è una copia del chip tagliata da un clip-path a cerchio che cresce dal punto premuto (dal centro coi tasti) fino all’angolo più lontano. Anche le camere sono pulsanti radio, con una spunta che salta fuori. I dati si controllano su Continue: i campi vuoti o a metà diventano rossi, tremano con dei keyframes e dicono il perché, poi si ricontrollano mentre si scrive; la scheda cresce piano coi messaggi.

Il riepilogo e il totale

All’ultimo passo il riepilogo si scrive dalle scelte (le date calcolate su giugno 2026, le notti, il prezzo della camera) e il totale conta da zero; le parole del pulsante scorrono e la sua larghezza va da una parola all’altra. Confermando, un arco gira per un attimo, poi l’ultimo pannello: l’anello e la spunta si disegnano e i passi fanno un’onda (su e giù, uno dopo l’altro).

Tastiera e anteprima

È un modulo vero: Invio va avanti, i passi fatti sono pulsanti che tornano indietro (gli altri sono disattivati), il passo in corso ha aria-current step e ogni pannello nuovo prende la focalizzazione sul suo titolo. Un clic da script (l’anteprima della libreria) cambia una scelta e va avanti, scrive i dati, prenota e ricomincia, senza prendere la focalizzazione.

Valori da cambiare

NomeFileDi partenzaCosa cambia
SLIDEscript.js48Di quanti pixel scivola un pannello entrando e uscendo.
MOVEscript.js0.5I secondi del cambio fra due pannelli.
FILLscript.js0.6I secondi che la linea impiega ad arrivare al passo dopo.
ROOMSscript.js[['Garden room', 'Looks onto the lemon trees', 120], …]Le camere: nome, una riga che la descrive e il prezzo di una notte.

Provali nel Playground

Quando usarla

Per prenotare una camera o un tavolo, un ordine, un’iscrizione, un preventivo, un acquisto in più passaggi: ovunque un modulo lungo si divide in passi.

Sul telefono

La scheda prende la larghezza dello schermo; i passi restano in fila con le loro icone, i chip vanno a capo e i campi aprono la tastiera giusta (quella dell’email per l’email).

Con il movimento ridotto

I pannelli cambiano subito, senza scivolare, la linea e i passi arrivano al nuovo stato senza animazione, il miele dei chip è subito pieno, il totale compare già fatto e l’anello e la spunta della fine sono già disegnati.

Trappole

  • Per animare l’altezza della scheda fra due pannelli servono le due misure: il pannello che esce va tolto dal flusso (position absolute dov’era) prima di misurare quello che entra.
  • Un clip-path come stringa non sempre si anima: il browser lo può riscrivere in un’altra forma e il tween salterebbe. Il raggio del cerchio si anima come numero e il clip-path si scrive a ogni fotogramma.
  • Il totale che conta, se fosse dentro l’animazione del cambio di pannello, terrebbe occupato il pulsante per tutto il conteggio: conta per conto suo.
  • Un pannello nascosto non ha misure: i chip scelti mentre il loro pannello non si vede si riempiono col cerchio in percentuale, non in pixel.

Librerie

GSAP 3.15.0, Red Hat Display (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 10 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 3 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Fatto

Licenza d’uso

Puoi usarla nei tuoi progetti e in quelli dei tuoi clienti. Non puoi rivenderla né ridistribuirla così com’è. GSAP resta sotto la sua licenza Standard. Licenza completa.

Tutti i componenti