1. Warum das Erscheinungsbild überhaupt steuern
Ihr Widget sieht vermutlich wie eine „normale React‑Komponente“ aus: ein div, eine Liste von Elementen, ein paar Buttons. Im normalen Web reicht das oft. In ChatGPT gibt es jedoch eine Besonderheit: Ihre UI lebt innerhalb des Chats, wo der Nutzer bereits viel visuellen Kontext hat – Nachrichten, andere Apps, Sprachoberfläche – plus Größenbeschränkungen des Containers.
Merken Sie sich zwei Dinge.
Erstens hat das Widget einen Anzeigemodus (displayMode): inline, fullscreen, manchmal PiP. Vom Modus hängen verfügbare Fläche, Scroll‑Verhalten und Nutzererwartungen ab.
Zweitens informiert die Plattform das Widget über Höhenbeschränkungen (maxHeight) und das Thema (theme). Wenn Sie das ignorieren und etwas in Notion‑Größe innerhalb einer einzelnen Nachricht rendern, wird der Chat zu einem „schwarzen Loch“, in dem alles in einem riesigen iframe versinkt. OpenAI empfiehlt ausdrücklich, die UI knapp zu halten und Systemfarben/Typografie zu respektieren.
Ein typisches GiftGenius‑Szenario zeigt gut, wie das in der Praxis funktioniert. Der Nutzer bittet: „Finde ein Geschenk für einen Freund bis $50“. ChatGPT startet GiftGenius, das im Inline‑Modus kompakte Geschenkkarten und ein paar Buttons zeigt. Der Nutzer klickt „Mehr Details“ – das Widget fordert Fullscreen an und zeigt dort Filter, detaillierte Beschreibung, Bewertungen. Während des Checkouts kann man ein kleines PiP/Modal mit dem Status „Bestellung wird verarbeitet …“ einblenden, ohne den ganzen Chat zu überdecken.
Unser Ziel in dieser Vorlesung ist es, zu lernen:
- zu verstehen, welcher displayMode aktiv ist, und angemessen darauf zu reagieren;
- den Modus auf Anfrage umzuschalten (inline ↔ fullscreen, gelegentlich PiP);
- maxHeight zu respektieren und kein „doppeltes Scrollen“ zu erzeugen;
- Stile an helles/dunkles Thema und die Bildschirmbreite anzupassen;
- ein Layout zu bauen, das sich „heimisch“ in ChatGPT anfühlt.
2. Modi von displayMode: inline, fullscreen, PiP
Fangen wir mit den Begriffen an. displayMode ist der Zustand des Containers Ihres Widgets in ChatGPT. Er kommt von der Plattform (über window.openai.displayMode oder den Hook useDisplayMode) und kann Werte wie "inline", "fullscreen", "pip" annehmen.
Inline
Inline ist der Standardmodus. Das Widget wird direkt in den Nachrichtenfluss als weiterer „Block“ zwischen Textantworten eingefügt. Die Breite ist durch die Chat‑Spalte begrenzt (auf dem Desktop ~700–800px, auf dem Telefon durch die Bildschirmbreite), die Höhe ist dynamisch, aber nicht unendlich.
Inline eignet sich ideal für:
- kurze, in sich geschlossene Darstellungen: Geschenkkarten, Optionsliste, Suchzusammenfassung;
- ein oder zwei Aktionen: „Auswählen“, „Abbrechen“, „Mehr anzeigen“.
Für GiftGenius ist das der Hauptmodus: Der Nutzer schreibt eine Anfrage, und Sie zeigen 3–5 Geschenkkarten mit Buttons – ohne den gesamten Bildschirm zu vereinnahmen.
Fullscreen (Canvas)
Fullscreen (oder Canvas) bedeutet, dass Ihr Widget den Großteil des sichtbaren Bereichs einnimmt. Der Chat verschwindet dabei nicht: Die Eingabezeile ist weiterhin verfügbar, aber die Hauptaufmerksamkeit liegt auf Ihrer UI.
Fullscreen zu aktivieren ist sinnvoll, wenn:
- es viele Eingabefelder oder einen komplexen Assistenten gibt (Checkout, komplexe Filter, Einstellungen);
- große Tabellen, Karten oder Vergleiche Dutzender Elemente gezeigt werden sollen;
- Inline nicht mehr reicht und wie ein Mini‑Excel mit 700px Höhe wirkt.
In GiftGenius ist Fullscreen nötig, um dem Nutzer vollwertige Filter, Sortierung, detaillierte Beschreibungen und eventuell mehrere Tabs zu geben.
PiP / Modal
PiP (picture‑in‑picture) und Modals sind kleine „schwebende“ Fenster über dem Hauptinhalt. In aktuellen Apps‑SDK‑Implementierungen wird PiP oft entweder als besonderer displayMode oder als Modal über requestModal() umgesetzt.
Sie sind nützlich, wenn:
- der Status eines langen Prozesses angezeigt werden soll (Bestellverarbeitung, Video‑Rendering);
- schnell etwas Kleines gefragt werden soll, ohne den Hauptfluss zu unterbrechen (kurze Bestätigung);
- Sie dem Nutzer die Möglichkeit geben wollen, „das Widget im Blick zu behalten“ und trotzdem weiter zu chatten.
In GiftGenius könnte das ein kleines Panel „Bestellung wird verarbeitet … 30 %“ mit einem Button „Abbrechen“ sein.
Kleiner Vergleich
Tabelle zur visuellen Einordnung:
| Modus | Ort | Typische Anwendungsfälle | Einschränkungen |
|---|---|---|---|
|
im Nachrichtenfluss | Listen, Karten, ein bis zwei Buttons | Begrenzte Höhe, schmale Breite |
|
über dem Chat / seitlich | Assistenten, komplexe Formulare, Tabellen | Erfordert durchdachtes Layout und Navigation |
| PiP / modal | schwebende Ebene | Status, Mini‑Formulare, Video | Sehr wenig Platz, alles muss groß und einfach sein |
Wichtig ist, Fullscreen nicht als „echte App“ und Inline nicht als „Preview“ zu betrachten. Es ist dieselbe App – nur in unterschiedlichen „Posen“.
3. Hooks für die Arbeit mit dem Modus: useDisplayMode, useRequestDisplayMode, useRequestModal
Nachdem klar ist, was inline/fullscreen/PiP aus UX‑Sicht bedeuten, schauen wir, wie man aus dem Code via Hooks des Apps SDK damit arbeitet.
Anstatt window.openai.displayMode direkt zu lesen, nutzen wir einen Hook aus dem Template, der auf Änderungen hört und Sie vor Ritualtänzen mit SDK‑Events bewahrt. Ein typisches Interface sieht so aus:
// Pseudotypen, prüfen Sie die tatsächlichen Namen im Template
type DisplayMode = 'inline' | 'fullscreen' | 'pip';
function useDisplayMode() {
// gibt den aktuellen Modus zurück
return { displayMode: 'inline' as DisplayMode };
}
function useRequestDisplayMode() {
// Funktionsaufruf zur Modusänderung
return {
requestDisplayMode: (mode: DisplayMode) => {
/* ruft window.openai.requestDisplayMode auf */
},
};
}
Bauen wir eine einfache Komponente, die den aktuellen Modus anzeigt und einen „Auf/Zu“‑Button anbietet:
import { useDisplayMode, useRequestDisplayMode } from '@/apps-sdk';
export function DisplayModeDebug() {
const { displayMode } = useDisplayMode();
const { requestDisplayMode } = useRequestDisplayMode();
const toggle = () => {
requestDisplayMode(displayMode === 'inline' ? 'fullscreen' : 'inline');
};
return (
<div className="text-xs text-gray-500 flex gap-2 items-center">
<span>Modus: {displayMode}</span>
<button onClick={toggle} className="underline">
Umschalten
</button>
</div>
);
}
In echten Apps verstecken Sie solche „Debug“-Elemente normalerweise, aber im Dev‑Modus hilft so eine Komponente sehr dabei, zu spüren, wie sich das Widget beim Umschalten verhält.
Inline vs. Fullscreen mit unterschiedlichen Unterkomponenten
Ein häufiger Fehler ist der Versuch, alle Modi mit demselben Layout zu bedienen und den JSX mit vielen if (displayMode === ...) zu überfrachten. Wesentlich angenehmer ist es, die Darstellung zu trennen:
import { useDisplayMode } from '@/apps-sdk';
import { GiftListInline } from './GiftListInline';
import { GiftListFullscreen } from './GiftListFullscreen';
export function GiftWidget() {
const { displayMode } = useDisplayMode();
if (displayMode === 'fullscreen') {
return <GiftListFullscreen />;
}
return <GiftListInline />;
}
So liest sich der Code wie „wenn fullscreen – dann der komplexe Assistent, sonst – das kompakte Inline“. Und jede Unterkomponente kann separat für ihre Einschränkungen gestylt werden. Genau dieser Ansatz wird im Modul empfohlen: die Modi auf eigene Unterkomponenten aufteilen, statt ein riesiges if/else in einer Komponente.
Modals: useRequestModal
Wenn das Template den Hook useRequestModal bereitstellt, sieht dessen Interface meist so aus:
const { requestModal } = useRequestModal();
// requestModal({ title }) oder so ähnlich.
Modals ähneln in manchem dem Fullscreen, ersetzen ihn aber nicht: Fullscreen ist für große Szenarien, ein Modal für einen kurzen Schritt (Aktion bestätigen, Gutscheincode eingeben usw.).
4. Größenkontrolle: maxHeight, Scroll und notifyIntrinsicHeight()
Die zweite wichtige Achse ist die Höhe. Die Plattform sagt dem Widget: „Das ist die maximal verfügbare Höhe.“ Dieses Limit lässt sich über window.openai.maxHeight oder per Hook useMaxHeight auslesen.
Warum man nicht einfach „height: 5000px“ setzen kann
Wenn Sie maxHeight ignorieren und eine riesige feste Höhe setzen, muss ChatGPT Ihren Inhalt abschneiden. Oder es entsteht für den Nutzer ein doppeltes Scrollen: außen der Chat, innen Ihr Widget. Das ist schlechter UX: Der Nutzer muss raten, wo genau er scrollen soll, um die gewünschte Schaltfläche zu erreichen.
Die richtige Strategie ist:
- Das Limit maxHeight lesen.
- Das Layout so bauen, dass der Haupt‑Scroll beim Chat bleibt (vor allem im Inline‑Modus).
- Im Fullscreen darf es etwas inneren Scroll geben – aber behutsam.
useMaxHeight und Container begrenzen
Schreiben wir einen einfachen Wrapper, der die maximale Höhe für den Root‑Container setzt:
import { useMaxHeight } from '@/apps-sdk';
export function WidgetContainer(props: { children: React.ReactNode }) {
const { maxHeight } = useMaxHeight(); // z. B. 600
return (
<div
style={{ maxHeight }}
className="overflow-y-auto p-4 bg-background border border-border rounded-xl"
>
{props.children}
</div>
);
}
Hier begrenzen wir ehrlich die Höhe und aktivieren vertikalen Scroll im Container – aber in vernünftigen Grenzen. In der Praxis sollte man im Inline‑Modus großen inneren Scroll vermeiden und statt riesiger Listen einen Teil der Daten zeigen mit „Mehr anzeigen“ oder Fullscreen anbieten.
Dynamische Höhe und notifyIntrinsicHeight()
Noch ein Punkt: Ihr Inhalt kann seine Größe im Laufe der Zeit ändern. Zuerst zeigen Sie etwa einen Spinner „Geschenke werden geladen …“, danach eine Liste von 10 Karten, dann klappt der Nutzer Filter ein/aus. Damit ChatGPT dem Widget korrekt Platz zuweist und nichts abschneidet, sollten Sie bei Höhenänderungen dem Host den neuen Wert melden. Dafür gibt es notifyIntrinsicHeight().
Im Template ist das oft in einen Hook wie useAutoResize gewickelt. Man kann ihn ungefähr so implementieren:
import { useEffect, useRef } from 'react';
import { useNotifyIntrinsicHeight } from '@/apps-sdk';
export function useAutoResize() {
const ref = useRef<HTMLDivElement | null>(null);
const { notifyIntrinsicHeight } = useNotifyIntrinsicHeight();
useEffect(() => {
if (!ref.current) return;
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
notifyIntrinsicHeight(entry.contentRect.height);
}
});
observer.observe(ref.current);
return () => observer.disconnect();
}, [notifyIntrinsicHeight]);
return ref;
}
Und so verwenden Sie es:
export function GiftListInline() {
const containerRef = useAutoResize();
return (
<div ref={containerRef}>
{/* Ihr Inhalt */}
</div>
);
}
Die Idee ist einfach: Wenn Ihr Root‑div seine Höhe ändert, rufen Sie die SDK‑API auf und ChatGPT passt den Container an. Dieses Muster wird von erfahrenen Entwicklern ausdrücklich empfohlen: ein „Auto‑Resizer‑Wrapper“ um den gesamten Inhalt.
Kleines Schema
Stellen wir es als Ablauf dar:
flowchart TD
A[Widget-Inhalt hat sich geändert] --> B[ResizeObserver erfasst die neue Höhe]
B --> C["Aufruf von notifyIntrinsicHeight(newHeight)"]
C --> D[ChatGPT vergrößert/verkleinert den Container]
D --> E[Der Nutzer sieht sauberes Scrollen ohne Abschneiden]
Damit wären die Größen und die Höhe geklärt: Das Widget soll den zugewiesenen Platz einhalten und dem Nutzer keine Aufgabe mit doppeltem Scrollen stellen.
5. Thema (theme), Farben und Rahmen: den Widget‑Look „heimisch“ machen
Wenn displayMode und maxHeight bestimmen, wieviel Platz wir haben, dann sorgen Thema (theme) und Farbpalette dafür, wie dieses Stück UI im Chat wirkt.
ChatGPT unterstützt mindestens helles und dunkles Thema. Die Plattform übermittelt das an Ihr Widget über window.openai.theme und/oder in _meta["openai/theme"], und im React‑Template gibt es einen Hook wie useOpenAiGlobal("theme") oder useTheme.
Die Hauptaussage: Ihre UI soll sich dem Thema anpassen, nicht ihr eigenes aufzwingen.
Thema beziehen
Beispiel für einen einfachen Hook:
import { useOpenAiGlobal } from '@/apps-sdk';
export function useThemeMode() {
const theme = useOpenAiGlobal<'light' | 'dark'>('theme') ?? 'light';
return { theme };
}
In der Komponente:
export function ThemedCard(props: { children: React.ReactNode }) {
const { theme } = useThemeMode();
const className =
theme === 'dark'
? 'bg-slate-900 text-slate-100 border-slate-700'
: 'bg-white text-slate-900 border-slate-200';
return (
<div className={`rounded-xl border p-4 ${className}`}>
{props.children}
</div>
);
}
Im realen Projekt verwenden Sie wahrscheinlich Tailwind mit darkMode: 'class' und hängen die Klasse dark an den Root‑Container des Widgets. Das ändert aber nichts am Kern: Das Thema kommt aus dem Apps SDK und „lebt“ nicht für sich.
Farben, Rahmen und Typografie
Laut OpenAI‑Guides:
- nutzen Sie Systemschriften und eine saubere Typografie;
- überschreiben Sie Systemfarben nicht aggressiv;
- das Widget soll ein „heimisches“ Element des Chats sein, nicht eine eigene Landingpage mit grellem Verlauf.
Gutes Pattern für einen GiftGenius‑Container:
export function GiftCard(props: { title: string; price: string }) {
return (
<div className="rounded-xl border border-border bg-background p-3 flex flex-col gap-2">
<div className="font-medium text-foreground">{props.title}</div>
<div className="text-sm text-muted-foreground">{props.price}</div>
<button className="self-start px-3 py-1 text-sm rounded-full bg-primary text-primary-foreground">
Auswählen
</button>
</div>
);
}
Hier wird angenommen, dass bg-background, border-border, text-foreground, bg-primary usw. CSS‑Variablen/Utility‑Klassen sind, die an das ChatGPT‑Thema gebunden sind. Dieser Ansatz steht so auch in den Empfehlungen: Variablen und Klassen, die am Thema hängen, statt hart kodierter Farben.
6. Layout und Responsiveness: Desktop, Mobile, PiP
Die dritte Achse ist die Breite und das Gerät. Sehr vereinfacht wird das Erscheinungsbild Ihres Widgets durch den Modus (displayMode), die verfügbare Höhe (maxHeight) und die verfügbare Breite (Desktop/Mobile/PiP) bestimmt.
In diesem Abschnitt kümmern wir uns um den dritten Parameter. Auf dem Desktop hat das Inline‑Widget eine andere Breite als auf dem Mobilgerät; in PiP ist der Platz sehr knapp. Das Apps SDK liefert Signale wie userAgent, safeArea, teils auch die Containergröße, die man über useOpenAiGlobal lesen kann.
Allgemeine Prinzipien
Einige wichtige Prinzipien:
Erstens: Verlassen Sie sich nicht auf feste Breiten. Der Bildschirm des Nutzers kann schmal (Telefon) oder breit (großer Desktop) sein. Bauen Sie das Layout lieber mit Flex/Grid und auto‑fit statt mit hartem width: 400px.
Zweitens: Vermeiden Sie horizontales Scrollen. Wenn Ihre Tabelle oder Karten nicht passen, wechseln Sie besser in den Fullscreen oder zeigen eine gekürzte Version. Alternativ geht eine Karussell‑Ansicht.
Drittens: Beachten Sie, dass PiP/Modals oft sehr schmal sind – dort passt kein großes Formular hinein; es ist physisch schwer, Felder zu treffen.
Diese Punkte werden in der Doku deutlich hervorgehoben: Responsiveness, safeArea, Unterschiede Desktop vs. Mobile und die Gefahr überladener Layouts.
Unterschiedliche Layouts für Inline und Fullscreen
Zurück zu GiftGenius. Die Geschenkliste kann in Inline und Fullscreen sehr unterschiedlich aussehen. Bauen wir zwei Komponenten.
Kompaktes Inline: maximal 3 Karten, eine Spalte auf Mobile und zwei auf breitem Bildschirm.
export function GiftListInline() {
const gifts = useGiftData(); // hypothetischer Hook, aus toolOutput
return (
<WidgetContainer>
<h2 className="text-base font-semibold mb-3">
Geschenkauswahl
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{gifts.slice(0, 3).map(gift => (
<GiftCard
key={gift.id}
title={gift.title}
price={`${gift.price} $`}
/>
))}
</div>
{gifts.length > 3 && (
<p className="mt-3 text-xs text-muted-foreground">
Die ersten 3 Optionen werden angezeigt. Erweitern Sie das Widget, um alles zu sehen.
</p>
)}
</WidgetContainer>
);
}
Und die Fullscreen‑Version: Grid, Filter, mehr Karten.
export function GiftListFullscreen() {
const gifts = useGiftData();
const [query, setQuery] = useState('');
const filtered = gifts.filter(g =>
g.title.toLowerCase().includes(query.toLowerCase()),
);
return (
<div className="h-full flex flex-col gap-4 p-4">
<header className="flex gap-2 items-center">
<h1 className="text-lg font-semibold flex-1">
Geschenke für Sie
</h1>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="Nach Name filtern"
className="px-2 py-1 text-sm border rounded-md flex-1"
/>
</header>
<main className="flex-1 overflow-y-auto">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
{filtered.map(gift => (
<GiftCard
key={gift.id}
title={gift.title}
price={`${gift.price} $`}
/>
))}
</div>
</main>
</div>
);
}
Hier erlauben wir vertikalen inneren Scroll des Fullscreen‑Inhalts (overflow-y-auto auf main), was für den Vollbildmodus okay ist. Die Inline‑Version bleibt – wie in den Guides empfohlen – kompakt und „in 2 Sekunden erfassbar“.
Schaubild: Verhalten nach Modus
Zur Festigung eine einfache Diagramm‑Darstellung:
stateDiagram-v2
[*] --> Inline
Inline: 3 Karten, minimaler Text
Inline --> Fullscreen: Klick auf "Erweitern" / "Alles anzeigen"
Fullscreen: Raster, Filter, viele Daten
Fullscreen --> Inline: Button "Schließen" / Aktion des Hosts
Fullscreen --> PiP: Langer Vorgang, Fortschritt anzeigen
PiP: Kleine Statusleiste
PiP --> Inline: Vorgang abgeschlossen, Abschlussnachricht anzeigen
Dieses Szenario entspricht gängigen UX‑Mustern: Inline als Teaser, Fullscreen als Arbeitsoberfläche, PiP als Prozessindikator.
7. Praxis: zwei Modi desselben Widgets
Zeit, das im Code zu verankern. Als Übung in dieser Vorlesung bieten sich zwei Schritte im aktuellen Lernprojekt an.
Schritt 1. Inline‑Widget mit Karte
Erweitern Sie das aktuelle GiftGenius so, dass das Widget im Inline‑Modus:
- die Überschrift „Geschenkauswahl“ anzeigt;
- bis zu drei Geschenkkarten aus toolOutput darstellt;
- den Hinweis „Erweitern Sie das Widget, um alles zu sehen“ zeigt, wenn es mehr als drei Geschenke gibt;
- die Höhe sauber über useAutoResize und notifyIntrinsicHeight() anpasst.
Die Styles sollten sich dabei auf das Thema stützen: nutzen Sie Klassen oder Variablen, die an theme gebunden sind, und keine harten Farben.
Schritt 2. Fullscreen‑Version mit Formular
Fügen Sie dann eine Fullscreen‑Darstellung hinzu, die:
- Überschrift + Suche nach Name zeigt;
- alle Geschenke im Grid ausgibt;
- vertikalen Scroll innerhalb des Hauptbereichs erlaubt;
- einen Button „Zurück zum Dialog“ bereitstellt (der requestDisplayMode('inline') aufruft).
Die Komposition kann so aussehen:
export function GiftGeniusWidget() {
const { displayMode } = useDisplayMode();
return (
<>
<DisplayModeDebug />
{displayMode === 'fullscreen' ? (
<GiftListFullscreen />
) : (
<GiftListInline />
)}
</>
);
}
Im ChatGPT‑Dev‑Modus können Sie den Modus manuell umschalten oder Fullscreen programmgesteuert per Klick auf „Alles anzeigen“ in der Inline‑Version anfordern (über useRequestDisplayMode). Diese Übung festigt das Verständnis, wie dieselbe App je nach displayMode unterschiedlich aussehen und sich verhalten kann.
8. Typische Fehler bei der Steuerung des Widget‑Erscheinungsbilds
Bevor wir im Kurs weitergehen, halten wir ein paar typische Stolpersteine fest, die mit displayMode, Größen, Thema und Layout zusammenhängen. Wenn man sie von Anfang an vermeidet, macht das Arbeiten mit dem Apps SDK deutlich mehr Spaß.
Fehler Nr. 1: displayMode ignorieren und alles „zwangsweise“ fullscreen‑ähnlich machen.
Manchmal zeichnen Entwickler ein schweres Layout (fast wie eine eigene SPA), das gerade so ins Inline passt. Der Nutzer sieht dann ein Mini‑Notion mit Scrollbars und unzähligen Elementen. Der korrekte Ansatz ist, unterschiedliche Darstellungen für verschiedene Modi zu entwerfen und zu respektieren, dass Inline ein kompakter, „eine‑Bildschirm“-Formfaktor ist.
Fehler Nr. 2: Riesige feste Höhe und doppeltes Scrollen.
Einfach height: 800px setzen und maxHeight vergessen, führt entweder zum Abschneiden oder zu gleichzeitiger innerer und äußerer Scrollbar. Der Nutzer fängt an, die „richtige“ Scrollleiste zu suchen – das schadet dem UX stark. Stattdessen sollten Sie maxHeight lesen, per max-height begrenzen und bei Höhenänderungen über notifyIntrinsicHeight() informieren.
Fehler Nr. 3: Thema ignorieren und alles „auf Marke“ umfärben.
Wenn Sie eigene Schriften, Hintergründe, harte Verläufe setzen und helles/dunkles ChatGPT‑Thema komplett ignorieren, zerstören Sie die visuelle Einheit der Plattform. Die Guides sagen klar: Systemfarben und -schriften nutzen, Marke dezent durch Akzente einbringen (Button, Icon, Logo). Behalten Sie theme via Hook im Blick und passen Sie die Palette an.
Fehler Nr. 4: Zu komplexe UI in PiP/Modals.
Zu versuchen, ein komplettes Formular mit vielen Feldern in ein kleines PiP‑Fenster zu quetschen, führt nirgendwohin. Dort passen nur sehr einfache Fälle: Prozessfortschritt, ein bis zwei Buttons, ein Eingabefeld. Alles andere ist ein Kandidat für Fullscreen.
Fehler Nr. 5: Hart auf 800px layouten und nicht auf Mobilgeräten testen.
Hart auf 800px zu layouten und zu glauben, „irgendwie wird es auf dem Telefon schon passen“. In Wirklichkeit hat der mobile ChatGPT‑Client ganz andere Breite und Verhalten, und PiP ist noch schmaler. Denken Sie an userAgent/safeArea, nutzen Sie Grid/Flex ohne feste Breite und schauen Sie Ihr Widget wenigstens einmal in einem schmalen Layout an.
Fehler Nr. 6: Direkte Arbeit mit window.openai ohne Hooks.
Formal können Sie schreiben: const mode = window.openai.displayMode, müssen dann aber selbst Events abonnieren, über React‑Updates nachdenken und Bugs jagen, falls das SDK etwas ändert. Die Hooks (useDisplayMode, useMaxHeight, useOpenAiGlobal, useRequestDisplayMode) sind genau dafür da, diese Routine zu kapseln und den Code sauber zu halten. Nutzen Sie sie – und leben Sie entspannter.
GO TO FULL VERSION