CodeGym /Corsi /ChatGPT Apps /Pattern inline: schede, elenchi, caroselli e CTA

Pattern inline: schede, elenchi, caroselli e CTA

ChatGPT Apps
Livello 8 , Lezione 1
Disponibile

1. Che cos’è la modalità inline e perché è il «default»

Le linee guida ufficiali di OpenAI sottolineano: la visualizzazione inline è la modalità principale per le ChatGPT Apps. Un widget inline viene renderizzato direttamente nel flusso della chat sopra la risposta del modello e include un piccolo blocco UI (scheda, elenco, carosello) più un messaggio di follow‑up di GPT sotto.

L’idea è semplice: invece di portare l’utente in un’interfaccia grande e separata, gli offriamo un «colpo d’occhio» compatto direttamente nel contesto della conversazione: il modello spiega cosa è successo e quali sono le opzioni successive, mentre il widget mostra in modo pulito la struttura e le azioni disponibili.

Un widget inline:

  • è leggero nei contenuti e non richiede molti passaggi;
  • non porta l’utente in una navigazione complessa con tab e barre di scorrimento interne;
  • risolve una‑due piccole esigenze: mostrare un elenco di opzioni, permettere una scelta, confermare un’azione, mostrare uno stato.

La modalità fullscreen (ne parleremo nella prossima lezione) serve per wizard articolati e contenuti complessi. Per ora conta questo: per impostazione predefinita pensate in inline, e abilitate il fullscreen consapevolmente, quando l’inline chiaramente non basta più.

Il nostro obiettivo in questa lezione è imparare a usare con sicurezza tre pattern inline principali e, sopra di essi, lavorare con le CTA:

  • schede
  • elenchi
  • caroselli

e applicare correttamente su di essi le CTA (Call to Action).

2. Quando inline è meglio di fullscreen

Semplificando, la modalità inline è un «assistente rapido», mentre il fullscreen è «un’app separata dentro ChatGPT».

Inline è particolarmente indicato quando:

  • serve mostrare alcune opzioni e farne scegliere una o due;
  • il risultato può essere espresso in una struttura compatta: scheda regalo, riepilogo ordine, mini tabella;
  • l’utente compie un’azione breve: «scegli», «mostra dettagli», «modifica filtro»;
  • il dialogo resta centrale: GPT spiega, scherza, commenta e il widget offre solo una forma o un visual comodo.

In termini di GiftGenius, inline significa:

  • mostrare 3–5 migliori regali per la persona selezionata;
  • dare un filtro rapido: «mostra solo regali digitali»;
  • confermare la scelta: «ecco il riepilogo dell’ordine, è tutto ok?».

Il fullscreen tornerà utile più avanti per un wizard in tre passaggi di checkout complesso. Per ora restiamo nella zona leggera: una risposta di uno strumento → un widget inline.

Per chiarezza — una piccola tabella:

Pattern Quando è l’ideale Esempio in GiftGenius
Scheda 1–3 entità con parametri chiave e CTA 3 regali top
Elenco 5–10 voci testuali, priorità alla leggibilità elenco di idee senza immagini
Carosello 3–8 varianti simili con immagini, serve scorrimento lista lunga di regali

Chiarito questo, scendiamo alla concretezza: come si realizzano questi pattern in UI e codice. Proseguiremo per ogni pattern nello stesso formato: prima — cosa sono dal punto di vista UX, poi — un componente React semplice per GiftGenius e, infine, come si integra tutto ciò nel widget inline.

3. Schede: il mattone base dell’UI inline

Che cos’è una scheda nel contesto dell’Apps SDK

Secondo le linee guida di OpenAI, una scheda inline è un widget leggero, monopersona, che mostra una piccola quantità di dati strutturati e 1–2 azioni in basso. Può avere un titolo, un’immagine, un paio di righe di metadati e un pulsante CTA primario (più un secondario opzionale).

In GiftGenius ogni scheda rappresenta un regalo. È comodo includere:

  • il nome del regalo;
  • il prezzo;
  • per chi è adatto (ad esempio, «collega», «amico stretto»);
  • una breve spiegazione del perché è una buona opzione;
  • il pulsante «Scegli questo regalo» oppure «Dettagli».

La scheda deve essere autosufficiente: con un colpo d’occhio l’utente capisce che cos’è l’entità e qual è l’azione principale.

Tipo di dato e semplice componente GiftCard

Per prima cosa definiamo il tipo di dato per un regalo. Supponiamo di avere già un ToolOutput con un array di tali oggetti; qui ci interessa solo la parte UI.

// Struttura generale del regalo per la UI
export type GiftSuggestion = {
  id: string;
  title: string;
  priceLabel: string;         // ad esempio "≈ 40 $"
  recipientLabel: string;     // "per un collega"
  reason?: string;            // spiegazione dal modello
  imageUrl?: string;
};

Ora creiamo un semplice componente React della scheda:

type GiftCardProps = {
  gift: GiftSuggestion;
  onSelect: (gift: GiftSuggestion) => void;
};

export function GiftCard({ gift, onSelect }: GiftCardProps) {
  return (
    <div className="flex flex-col gap-2 rounded-lg border p-3">
      <div className="text-sm font-medium">{gift.title}</div>
      <div className="text-xs text-muted-foreground">
        Per: {gift.recipientLabel} · {gift.priceLabel}
      </div>
      {gift.reason && (
        <div className="text-xs text-muted-foreground">{gift.reason}</div>
      )}
      <button
        className="mt-2 self-start rounded bg-primary px-3 py-1 text-xs text-primary-foreground"
        onClick={() => onSelect(gift)}
      >
        Scegli questo regalo
      </button>
    </div>
  );
}

Qualche dettaglio subito:

  • non sovraccarichiamo la scheda di testo, massimo 2–3 righe di metadati e una breve spiegazione;
  • una CTA principale — «Scegli questo regalo»; non proviamo a infilarci 5 varianti diverse;
  • il componente è facilmente riutilizzabile sia in un elenco inline sia dentro un carosello.

Come le schede si inseriscono nel widget complessivo

Supponiamo di avere un array gifts ottenuto dopo la chiamata allo strumento giftgenius.suggestGifts tramite il nostro MCP. Il widget in modalità inline può semplicemente renderizzarle in una griglia da 1–3 colonne.

type GiftGridProps = {
  gifts: GiftSuggestion[];
  onSelect: (gift: GiftSuggestion) => void;
};

export function GiftGrid({ gifts, onSelect }: GiftGridProps) {
  return (
    <div className="grid gap-3 sm:grid-cols-2">
      {gifts.map((gift) => (
        <GiftCard key={gift.id} gift={gift} onSelect={onSelect} />
      ))}
    </div>
  );
}

Qui:

  • usiamo una griglia a 1–2 colonne, per non trasformare il widget in un «muro di mattoni»;
  • possiamo limitare facilmente il numero di schede, ad esempio mostrando solo le prime 3–6.

L’handler onSelect può chiamare uno strumento di checkout o semplicemente salvare la scelta nel Widget State e lasciare che il modello continui il dialogo. Un esempio minimale di integrazione con uno strumento:

async function handleSelect(gift: GiftSuggestion) {
  await window.openai.actions.call("giftgenius.startCheckout", {
    giftId: gift.id,
  });
}

Qui window.openai.actions.call è un bridge per invocare uno strumento MCP registrato direttamente dal widget.

Di solito dopo tale chiamata il modello mostrerà uno stato oppure aprirà il passo successivo (ad esempio, un riepilogo dell’ordine). L’importante è non provare a mettere tutta la logica di checkout dentro la scheda; la scheda deve avviare il passo successivo in modo chiaro.

4. Elenchi: quando l’aspetto visivo non è la priorità

Se la scheda è un piccolo «poster», l’elenco è un elenco testuale pulito. La documentazione e le raccomandazioni UX mostrano che gli elenchi sono ideali quando conta di più il contenuto testuale rispetto a un accento visivo forte.

Un elenco è adatto quando:

  • serve mostrare 5–10 opzioni che non richiedono un’immagine;
  • l’utente vuole «scorrere con lo sguardo» nomi e brevi descrizioni;
  • le azioni per ogni voce sono identiche e l’UI non deve distrarre.

Esempi in GiftGenius:

  • elenco di idee «veloci» per regali senza dettagli;
  • elenco di categorie preferite: «per i colleghi», «per i genitori», «per i bambini»;
  • elenco di raccolte salvate («Regali per il reparto HR», «Pensierini di Capodanno fino a $20»).

Componente elenco semplice

Creiamo un elenco compatto con una sola CTA «Mostra dettagli» a destra.

type GiftListProps = {
  gifts: GiftSuggestion[];
  onSelect: (gift: GiftSuggestion) => void;
};

export function GiftList({ gifts, onSelect }: GiftListProps) {
  return (
    <ul className="flex flex-col gap-2">
      {gifts.map((gift) => (
        <li
          key={gift.id}
          className="flex items-center justify-between rounded-md border px-3 py-2 text-sm"
        >
          <span className="truncate">{gift.title}</span>
          <button
            className="text-xs text-primary"
            onClick={() => onSelect(gift)}
          >
            Mostra dettagli
          </button>
        </li>
      ))}
    </ul>
  );
}

Qui noi:

  • applichiamo truncate al titolo per evitare che nomi lunghi rompano il layout;
  • usiamo di nuovo una sola CTA per elemento;
  • lasciamo le informazioni «ricche» (descrizione, immagine, recensioni) al passo successivo — ad esempio, al clic si apre una scheda separata o una vista fullscreen.

L’elenco si combina particolarmente bene con le proposte di follow‑up di GPT. Il widget mostra l’elenco dei «candidati» e, sotto, GPT scrive qualcosa come:

«Posso restringere ai regali fino a $30 o mostrare solo quelli digitali. Che cosa scegliamo?» e propone due‑tre pulsanti di follow‑up.

In una sezione separata analizzeremo meglio come combinare i widget inline e i messaggi di follow‑up in diversi scenari.

5. Caroselli: quando le opzioni sono molte, ma simili

Un carosello è un insieme di schede disposte orizzontalmente e sfogliate con swipe o pulsanti di navigazione. Le linee guida raccomandano i caroselli quando si mostra un piccolo elenco di elementi simili (di solito 3–8), ognuno con immagine, titolo e pochi metadati.

L’idea principale: l’utente può scansionare rapidamente l’insieme delle varianti senza addormentarsi sotto un elenco verticale infinito.

In GiftGenius il carosello è utile se:

  • abbiamo 10–15 regali adatti, ma il widget inline deve mostrarne solo una «top eight»;
  • ogni regalo è gradevole visivamente (immagine, presentazione);
  • è importante che l’utente sfogli le varianti senza scorrere troppo verso il basso nella chat.

Regole UX per i caroselli

Basate su linee guida e ricerca:

  • numero di schede nel carosello — da 3 a 8; se sono di più, meglio offrire un comando separato «Mostra di più»;
  • ogni scheda:
    • deve avere un’immagine o un altro elemento visivo;
    • non deve contenere più di due righe di testo‑metadati;
    • ha una CTA chiara, ad esempio «Scegli» o «Mostra dettagli»;
  • niente navigazioni annidate complesse (tab, sottopercorsi) dentro la scheda;
  • evitare barre di scorrimento interne (verticali): l’altezza della scheda si adatti fino a un limite ragionevole, ma senza barra propria.

Carosello semplice con il principio «una scheda alla volta»

Per evitare uno scroll orizzontale complesso, si può implementare la variante più semplice: mostrare una scheda alla volta e fornire i pulsanti «precedente/successivo».

import { useState } from "react";

type GiftCarouselProps = {
  gifts: GiftSuggestion[];
  onSelect: (gift: GiftSuggestion) => void;
};

export function GiftCarousel({ gifts, onSelect }: GiftCarouselProps) {
  const [index, setIndex] = useState(0);
  const gift = gifts[index];

  return (
    <div className="flex flex-col gap-2">
      <GiftCard gift={gift} onSelect={onSelect} />
      <div className="flex items-center justify-between text-xs">
        <button
          disabled={index === 0}
          onClick={() => setIndex((i) => i - 1)}
        >
          ← Precedente
        </button>
        <span>
          {index + 1} / {gifts.length}
        </span>
        <button
          disabled={index === gifts.length - 1}
          onClick={() => setIndex((i) => i + 1)}
        >
          Successivo →
        </button>
      </div>
    </div>
  );
}

Questo dà già la sensazione di «carosello», e al contempo:

  • il codice resta compatto;
  • non bisogna lottare con la larghezza del contenitore e gli scroll orizzontali interni al widget;
  • è facile limitare gifts a 8 elementi prima di passarli al componente.

Se si desidera un carosello più «vero», si può usare overflow-x-auto e una larghezza fissa delle schede, ma in quel caso spesso conviene prendere un componente pronto da una libreria UI (shadcn/ui, soluzioni compatibili con Radix, ecc.) invece di reinventarlo da zero.

6. Pulsanti CTA: pochi, chiari, funzionali

Le CTA (Call to Action) sono il cuore di ogni pattern inline. Sono i pulsanti a trasformare il vostro widget da immagine a strumento operativo.

Principi fondamentali

La documentazione di OpenAI dà raccomandazioni piuttosto rigorose:

  • sulla scheda — al massimo due pulsanti primari (uno principale, uno secondario);
  • nel carosello — possibilmente una CTA per elemento;
  • il testo della CTA deve essere un verbo concreto: «Mostra dettagli», «Aggiungi alla lista», «Vai al pagamento», non astratti come «Ok» o «Azione».

Meno pulsanti, meglio è per modello e utente. Ricordate che sopra e sotto il widget c’è anche la parte testuale della risposta, più le proposte di follow‑up di GPT.

Collegare le CTA alla logica dell’applicazione

Nella nostra GiftGenius, la maggior parte delle CTA o:

  • modifica filtri/criteri di ricerca (nuova tool‑call giftgenius.refineSearch),
  • avvia il checkout (giftgenius.startCheckout),
  • apre un sito esterno (tramite openExternal, già visto nelle lezioni precedenti).

Esempio di handler semplice per la CTA «Modifica filtri»:

async function handleRefineFilters(gift: GiftSuggestion) {
  await window.openai.actions.call("giftgenius.refineSearch", {
    baseGiftId: gift.id,
  });
}

Dal punto di vista UX è molto importante esplicitare nelle system‑instructions quando e quali pulsanti CTA il modello deve proporre. Per esempio:

  • se l’utente chiede «mostra altre opzioni», è meglio mostrare un nuovo carosello con il pulsante «Scegli»;
  • se si arriva all’acquisto, la CTA «Vai al pagamento» deve portare a una tool‑call che avvia il checkout ACP (lo vedremo nel modulo su commerce e pagamenti).

Un’altra buona pratica è non duplicare le funzioni di ChatGPT nelle CTA. Evitate pulsanti tipo «Chiedi a ChatGPT»: l’utente ha già il campo di input e la voce. Le linee guida raccomandano esplicitamente di evitare input «duplicati» dentro la scheda.

7. Inline + follow‑up: un gioco a due

Un widget inline non vive mai nel vuoto. La struttura della risposta di solito è questa:

  1. il modello decide di usare la vostra App e chiamare uno strumento;
  2. il vostro MCP restituisce i dati;
  3. ChatGPT renderizza il widget inline con quei dati;
  4. sotto, il modello aggiunge un breve testo di follow‑up e opzioni pronte per proseguire.

Per GiftGenius potrebbe apparire così:

  • widget inline: tre schede regalo con CTA «Scegli»;
  • testo sotto:
    «Ecco tre idee per un collega: una lampada da scrivania, un corso di public speaking e una gift card del bar. Posso: — mostrare solo opzioni fino a $30; — trovare altre idee nello stesso stile; — aiutarti a passare subito all’acquisto di una di queste.»

Nel follow‑up il modello può fare riferimento alle CTA del vostro widget («premi “Scegli” sotto l’opzione che ti piace») oppure proporre comandi testuali che porteranno di nuovo a una tool‑call e a un rerender dell’UI inline.

Ricordate: il widget non deve saper fare tutto. A volte è meglio lasciare parte dello scenario al dialogo testuale e usare il widget come «blocco visivo» dentro la conversazione.

8. Come si integra nel flusso generale di GiftGenius

Per maggiore chiarezza, riassumiamo in un semplice diagramma di sequenza:

sequenceDiagram
  participant U as Utente
  participant C as ChatGPT
  participant A as Widget GiftGenius
  participant B as MCP/Backend

  U->>C: "Trova 3 regali fino a $50 per un collega"
  C->>B: call_tool(giftgenius.suggestGifts)
  B-->>C: 3 migliori opzioni
  C->>A: render del widget inline (schede/carosello)
  A-->>U: schede con CTA "Scegli"
  U->>A: clic sulla CTA
  A->>B: call_tool(giftgenius.startCheckout)
  B-->>A: stato / link al pagamento
  A-->>U: riepilogo della scelta / stato
  C-->>U: follow-up: "Posso proporre altre idee o aiutare con il biglietto d’auguri"

Dal punto di vista architetturale:

  • l’MCP resta il «cervello» (selezione, business logic, ACP),
  • il widget è il «volto» (schede/elenchi/caroselli),
  • ChatGPT è il «conduttore del dialogo», che spiega cosa è successo e propone i passi successivi.

Per rendere fluido questo flusso:

  • non sovraccaricate il widget di azioni;
  • mantenete i dati nelle schede compatti;
  • pensate a quali opzioni di follow‑up saranno utili dopo ogni visualizzazione inline.

9. Un accenno al lato visivo dei pattern inline

Parleremo in dettaglio di design visivo in una delle prossime lezioni del modulo, ma alcuni punti critici per i pattern inline vale la pena citarli già ora.

Primo, assicuratevi che le vostre schede ed elenchi non sembrino un sito estraneo dentro ChatGPT. Colori e spaziature devono essere curati, senza gradienti acidi e senza font come Comic Sans. Il widget inline è parte dell’UI complessiva di ChatGPT, non un banner del 2007.

Secondo, evitate barre di scorrimento interne. Se la vostra scheda è così lunga da avere una propria barra di scorrimento, qualcosa non va: o state cercando di infilare troppo contenuto, o il pattern scelto è sbagliato (forse serve il fullscreen).

Terzo, controllate la densità:

  • tra le schede deve esserci uno spazio visibile;
  • la CTA deve essere facilmente cliccabile (padding adeguato);
  • il testo deve essere leggibile anche su mobile, senza font microscopici.

Potrebbero sembrare «pignolerie da designer», ma l’esperienza mostra che se il widget inline sembra «nativo», il modello lo usa più volentieri e gli utenti si confondono meno.

10. Pratica: come far evolvere GiftGenius a partire dalla lezione

Se volete fissare i concetti, ecco una checklist pratica semplice:

Per prima cosa prendete il risultato corrente dello strumento giftgenius.suggestGifts (array di regali) e:

  1. Implementate tre varianti di UI in un solo componente:
    • GiftGrid con schede;
    • GiftList con elenco testuale;
    • GiftCarousel con navigazione «precedente/successivo».
  2. Aggiungete a ciascuno una‑due CTA:
    • per le schede — «Scegli»;
    • per l’elenco — «Mostra dettagli»;
    • per il carosello — ancora «Scegli», più un pulsante sotto il widget «Mostra altre opzioni».
  3. In base allo stato (ad esempio, quanti regali totali ha restituito lo strumento) scegliete quale pattern usare:
    • se le varianti sono poche (≤ 3) — griglia di schede;
    • se ci sono molte idee testuali — elenco;
    • se ci sono molti regali visivi — carosello.

Così non solo vi eserciterete con l’UI, ma inizierete a pensare alla scelta dinamica del pattern in base al contesto, cosa che piace molto sia agli utenti sia ai revisori dello Store.

In generale, i pattern inline sono uno strato UI rapido e leggero, che vive direttamente nel flusso della chat e non tenta di sostituire un’app separata. Schede, elenchi e caroselli coprono l’80% dei casi tipici: mostrare opzioni, far scegliere e proseguire il dialogo in modo pulito.

Nella prossima lezione del modulo vedremo cosa fare quando l’inline «non regge» più: analizzeremo i wizard fullscreen, la modalità PiP e gli scenari in cui alla vostra App serve davvero uno schermo grande separato dentro ChatGPT.

11. Errori tipici nell’uso dei pattern inline

Errore n. 1: trasformare il widget inline in un mini‑sito.
A volte gli sviluppatori cercano di infilare in una singola scheda tab, accordion, form, tabelle e un mucchio di altri elementi. Il risultato è una UI pesante, che rompe il ritmo della chat e diventa scomoda su mobile. Le linee guida dicono chiaramente: niente navigazioni profonde e viste complesse dentro le schede inline; gli scenari complessi vanno portati in fullscreen.

Errore n. 2: troppe CTA.
«Mettiamo sulla scheda “Dettagli”, “Compra”, “Preferiti”, “Condividi”, “Segnala” e “Genera biglietto di auguri”?». Alla fine l’utente si perde, anche il modello, e cala la probabilità che venga premuto il pulsante giusto. Ricordate la regola: una CTA principale e al massimo una secondaria. Gli altri scenari è meglio spostarli nel messaggio di follow‑up di GPT o nei passaggi successivi.

Errore n. 3: mescolare elenco, schede e carosello nella stessa risposta senza motivo.
Se lo stesso contenuto viene mostrato ora come elenco, ora come schede, ora come carosello «solo perché possiamo», l’utente perde la sensazione di coerenza. Meglio scegliere un pattern per un certo tipo di risultato (ad esempio, idee senza immagini — elenco; regali con immagini — carosello) e mantenerlo.

Errore n. 4: schede troppo cariche di testo.
Una scheda con tre paragrafi di descrizione, tre prezzi e due blocchi «perché è fantastico» diventa un muro di testo. L’utente smette di «scannerizzarla» e scorre oltre. Cercate di lasciare in scheda solo il necessario: titolo, un parametro chiave, una ragione breve e la CTA. Tutto il resto può essere spiegato nella risposta testuale di GPT accanto.

Errore n. 5: affidarsi solo all’UI e ignorare il follow‑up del dialogo.
Capita di incontrare l’approccio «facciamo tutto con i pulsanti, l’utente non deve parlare». È in contrasto con l’idea stessa di ChatGPT. Il widget inline deve integrare il dialogo, non sostituirlo. Non dimenticate di progettare quali opzioni di follow‑up il modello potrebbe proporre sotto il widget: modificare i filtri, chiedere più opzioni, passare allo step successivo.

Errore n. 6: ignorare i limiti sul numero di elementi.
Un carosello con 25 schede o un elenco con 50 voci dentro un unico widget inline è il modo migliore per far scorrere tutto all’utente. La documentazione raccomanda 3–8 elementi nel carosello e 5–10 voci nell’elenco. Se i dati sono di più, è utile aggiungere una CTA tipo «Mostra di più» o «Mostra tutto in testo».

Errore n. 7: usare l’inline dove serve già il fullscreen.
È forte la tentazione di «fare tutto in inline», anche quando ci sono già 4 step, form con una decina di campi e tabelle grandi. Ne esce un mostro, oppure si finisce a inventare scroll annidati e pseudo‑stepper dentro le schede. Quando sentite che i passaggi e i campi diventano tanti — è il segnale per pensare al passaggio a un wizard fullscreen, lasciando l’inline per anteprime rapide e riepiloghi delle azioni.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION