All posts

ChatGPT App Display Mode Reference (June 2026)

Abe Wheeler
ChatGPT AppsChatGPT App TestingMCP AppsMCP App TestingMCP App FrameworkReferenceDeveloper Tools
ChatGPT App in inline display mode on wide screen.

ChatGPT App in inline display mode on wide screen.

The MCP Apps specification defines three display modes for interactive app UIs: inline, fullscreen, and pip. ChatGPT implements those modes as part of its Apps SDK and MCP Apps support, but the spec and the host UI answer different questions.

The spec tells you which mode names exist, how apps request mode changes, and how hosts report the mode they actually chose. ChatGPT’s UI behavior tells you what each mode feels like in a real product: where the iframe appears, how much room it gets, when the host provides controls, and which surfaces work best for different jobs.

TL;DR: Treat display mode as host state, not as a routing system. Read displayMode, check availableModes, and build the same resource so it can survive inline, fullscreen, and PiP. Inline is for compact conversation UI, fullscreen is for deeper workflows, and PiP is for persistent sessions that keep running while the conversation continues.

What Changed Since April 2026

The core three modes are the same, but the ecosystem around them is less ChatGPT-only now:

  • The MCP Apps spec now describes app-side and host-side display mode negotiation through appCapabilities.availableDisplayModes and HostContext.availableDisplayModes.
  • OpenAI’s current Apps SDK reference tells developers to prefer MCP Apps standard fields and the ui/* bridge by default, while using window.openai for ChatGPT-specific extensions.
  • sunpeak’s current React API separates reading mode from requesting mode changes: useDisplayMode() reads the current mode, and useRequestDisplayMode() asks the host to change modes.

That changes how you should write app code. Older examples often assumed “request fullscreen” meant “you are now fullscreen.” Current MCP Apps code should ask for a mode, then render from the mode the host reports back.

Display Modes at a Glance

ModeBest forMain constraintApp behavior
inlineCards, confirmations, carousels, small selectors, summariesConversation width and content heightFit content, avoid nested scrolling, offer expand when needed
fullscreenDashboards, editors, maps, tables, multi-step formsHost chrome, safe areas, and viewportOwn the full content area, keep internal navigation clear
pipLive sessions, media, collaboration, games, ongoing statusFloating window size and mobile fallbackKeep controls compact and keep state synchronized

Use this table to choose the first render mode. Do not use it to skip responsive layout. A user can start inline, expand to fullscreen, then return to the conversation while the same resource instance or a reloaded resource still needs to understand the current host state.

Inline Display Mode

Inline display mode on wide screen

Inline mode inserts your ChatGPT App resource in the flow of the conversation. OpenAI’s UI guidelines describe inline as the default starting surface for apps, and it is the right choice when the user can understand and act on the result without leaving the current turn.

Use inline for:

  • A status card after a tool call
  • A small chart or map preview
  • A carousel with a short list of options
  • A form with one or two decisions
  • A summary that can expand into fullscreen when the user wants more detail

The old version of this post focused on the exact ChatGPT DOM observed in April. That DOM can change, so the more durable rule is this: design inline content to fit its own content height and avoid nested scrolling. If your inline UI needs tabs, filters, drill-down navigation, or more than a couple of primary controls, start with an inline summary and offer fullscreen.

For dynamic content, test the states that change height:

  • Empty result
  • Loading result
  • Long text
  • Many rows
  • Validation errors
  • Locale changes that make labels longer

Inline bugs usually come from assuming a desktop width, assuming content will never wrap, or putting a scrollable panel inside a scrollable conversation.

Fullscreen Display Mode

Fullscreen display mode on wide screen

Fullscreen mode gives the app the main host surface. In ChatGPT, the host still owns the frame around the app: close controls, conversation context, the composer, safe areas, and any host chrome. Your resource owns the app content area inside that frame.

Use fullscreen for:

  • Dashboards with filters and tables
  • Rich editors
  • Maps and canvases
  • Multi-step setup flows
  • Document review
  • Any workflow where the user needs to compare details

Do not duplicate host controls inside your app. If the host provides close behavior, do not add another large close button unless your workflow needs a domain-specific action such as “Finish review” or “Submit changes.” Fullscreen should feel like the same app expanded, not like a separate website inside ChatGPT.

In CSS, prefer a stable shell that uses the host-provided viewport:

import { SafeArea, useDisplayMode, useViewport } from 'sunpeak';

function Dashboard() {
  const displayMode = useDisplayMode();
  const viewport = useViewport();
  const isFullscreen = displayMode === 'fullscreen';

  return (
    <SafeArea>
      <main
        className={isFullscreen ? 'grid h-full grid-rows-[auto_1fr]' : 'space-y-3'}
        style={isFullscreen ? { minHeight: viewport?.height } : undefined}
      >
        <header>Revenue dashboard</header>
        <section className={isFullscreen ? 'min-h-0 overflow-auto' : ''}>
          {/* Table, chart, or editor */}
        </section>
      </main>
    </SafeArea>
  );
}

The important bit is min-h-0 overflow-auto on the content area in fullscreen. Without it, tables and panels often overflow behind the composer or host chrome.

Picture-in-Picture Display Mode

Picture-in-picture display mode

PiP displays the app in a floating window while the conversation keeps going. OpenAI’s UI guidelines frame PiP as a persistent surface for ongoing or live sessions: games, media, collaboration, learning sessions, and other UIs that should remain visible while the user keeps prompting.

Use PiP when the app has state that matters over time:

  • A timer, call, or media session
  • A quiz or game
  • A live status monitor
  • A shared workspace where chat prompts update the UI
  • A compact preview that should stay visible while the user scrolls

PiP is also the easiest mode to misuse. Avoid stuffing a dashboard into PiP. If users need deep navigation or many controls, request fullscreen instead. PiP should answer “what is happening right now?” and offer a small number of actions.

On mobile, treat PiP as a request. ChatGPT may choose fullscreen or another mobile-appropriate layout because a floating window can crowd the conversation. Your component should read the actual mode after the request and render from that value.

Requesting Display Mode Changes

In MCP Apps, display mode changes are negotiated. The app can request a mode, but the host decides what it can support in the current context. The spec requires apps to declare supported modes during initialization and to check host-supported modes before asking for a change.

With sunpeak, use useDisplayMode() to read the mode and useRequestDisplayMode() to request a mode:

import { useDisplayMode, useRequestDisplayMode } from 'sunpeak';

function ExpandControls() {
  const displayMode = useDisplayMode();
  const { requestDisplayMode, availableModes } = useRequestDisplayMode();

  const canFullscreen = availableModes?.includes('fullscreen');
  const canPip = availableModes?.includes('pip');

  if (displayMode === 'fullscreen') {
    return null;
  }

  return (
    <div className="flex gap-2">
      {canPip && (
        <button type="button" onClick={() => requestDisplayMode('pip')}>
          Keep visible
        </button>
      )}
      {canFullscreen && (
        <button type="button" onClick={() => requestDisplayMode('fullscreen')}>
          Expand
        </button>
      )}
    </div>
  );
}

Tie requests to user actions. Do not auto-expand on mount. Hosts can ignore requests that are not tied to user intent, and users do not expect a chat card to take over the screen by itself.

If you are using the lower-level MCP Apps SDK, the same rule applies. app.requestDisplayMode({ mode }) returns the actual mode that the host set, which can differ from the requested mode.

How ChatGPT Apps Fit the MCP Apps Standard

ChatGPT Apps are MCP Apps running in ChatGPT. The current OpenAI Apps SDK reference describes the MCP Apps UI bridge as JSON-RPC over postMessage with ui/* methods and notifications. It also keeps window.openai as a compatibility layer and a place for ChatGPT-specific extensions such as file APIs, modal requests, and requestDisplayMode.

For portable app code, prefer standard MCP Apps concepts:

  • Tool results pass structuredContent to the UI.
  • UI resources render inside sandboxed iframes.
  • Host context reports displayMode, theme, viewport, locale, safe areas, and host capabilities.
  • The app asks for mode changes and renders from the host’s response.

Then use ChatGPT-specific APIs only when the feature is ChatGPT-specific. This keeps your display-mode logic usable in Claude, VS Code, Goose, Postman, MCPJam, and other MCP Apps hosts that support the same extension.

Layout Rules That Hold Up Across Modes

The exact host DOM is not a contract. These rules are more reliable:

  1. Read host context instead of window.innerWidth when the decision depends on the app container.
  2. Keep inline content height natural, and do not put a scrollable panel inside a small inline card.
  3. In fullscreen, create one scroll owner for the main content area.
  4. In PiP, keep state visible and controls small.
  5. Use SafeArea so mobile and host chrome do not cover important controls.
  6. Test every mode with long content, empty data, loading states, and errors.

If your app has one complex view, do not create three unrelated components for the three modes. Create one resource component with mode-specific layout branches at the edges: toolbar placement, number of columns, max visible rows, and whether deeper navigation is available.

Quick Reference

PropertyInlineFullscreenPiP
First renderCommon defaultUsually requestedUsually requested
Best contentCompact, direct, low navigationRich workflows and detailPersistent live state
Host chromeConversation flowFull host surface with system controlsFloating host container
ScrollingPrefer natural heightInternal app content scrollConstrained window scroll
Mobile behaviorUsually same concept with narrower widthPrimary expanded modeMay fall back to fullscreen
Mode changesOffer expand when usefulHost provides close behaviorOffer fullscreen for more detail

Testing Display Modes

You can toggle display modes in the sunpeak inspector without deploying to ChatGPT or using a paid account. Run your project locally, switch the display mode in the inspector sidebar, and verify the same resource in each host, theme, and viewport.

For automated tests, pass displayMode to inspector.renderTool:

import { test, expect } from 'sunpeak/test';

const modes = ['inline', 'pip', 'fullscreen'] as const;

for (const displayMode of modes) {
  test(`resource layout adapts to ${displayMode}`, async ({ inspector }) => {
    const result = await inspector.renderTool('show-dashboard', undefined, { displayMode });
    const app = result.app();

    await expect(app.getByRole('heading', { name: 'Revenue dashboard' })).toBeVisible();

    if (displayMode === 'fullscreen') {
      await expect(app.getByRole('button', { name: 'Expand' })).not.toBeVisible();
    } else {
      await expect(app.getByRole('button', { name: 'Expand' })).toBeVisible();
    }
  });
}

Add visual checks for the modes most likely to break:

test('dashboard visual states', async ({ inspector }) => {
  const result = await inspector.renderTool(
    'show-dashboard',
    { region: 'north-america' },
    { displayMode: 'fullscreen', theme: 'dark' }
  );

  await expect(result.app()).toHaveScreenshot('dashboard-fullscreen-dark.png');
});

These tests run locally and in CI against replicated ChatGPT and Claude runtimes. That gives you fast coverage for layout, host context, iframe traversal, and display-mode changes without spending host credits on every branch.

Final Checklist

Before shipping a ChatGPT App or MCP App with display-mode support, check:

  • Inline fits without nested scrolling.
  • Fullscreen has one clear scroll area and no controls hidden under host chrome.
  • PiP stays compact and still updates from conversation state.
  • Mode-switch controls only appear when availableModes includes the target mode.
  • The UI renders correctly when the host returns a different mode than requested.
  • E2E tests cover inline, fullscreen, and pip.
  • Visual tests include at least one narrow viewport and one long-content state.

Display modes are small as an API, but they shape the whole user experience. Build from host context, test the modes as real states, and keep the resource portable unless you need a ChatGPT-only feature.

Get Started

Documentation →
npx sunpeak new

Further Reading

Frequently Asked Questions

What are the three ChatGPT App display modes?

ChatGPT Apps and MCP Apps support three display modes: inline, fullscreen, and picture-in-picture (PiP). Inline embeds the app in the conversation, fullscreen gives the app the full host surface, and PiP keeps the app in a floating window while the conversation remains usable.

How does inline display mode work in ChatGPT Apps?

Inline display mode embeds your ChatGPT App directly in the conversation flow. Use it for cards, carousels, summaries, and small controls. In current ChatGPT behavior, inline starts as the default mode and the app height should fit its content rather than create nested scrolling.

How does fullscreen display mode work in ChatGPT Apps?

Fullscreen display mode expands the app into the main ChatGPT surface. Use it for richer workflows such as editors, dashboards, maps, and multi-step forms. The host provides system chrome and close behavior, so your app should focus on the content area.

How does picture-in-picture (PiP) display mode work in ChatGPT Apps?

PiP displays the app in a floating window that remains visible while the user continues the conversation. It is best for live sessions, games, media, collaboration, or stateful activities that should stay present while prompts continue.

Does maxHeight apply in all ChatGPT App display modes?

No. In current ChatGPT behavior, maxHeight matters most for picture-in-picture and constrained inline surfaces. Fullscreen should use the available viewport and its own internal layout. Always read host context rather than hard-coding viewport assumptions.

What happens to ChatGPT App PiP mode on mobile devices?

ChatGPT may promote PiP-style experiences into fullscreen or another mobile-friendly surface on narrow screens. Treat PiP as a requested mode, not a guaranteed mode. Read the actual displayMode from host context and make every mode responsive.

How can I test different ChatGPT App display modes during development?

Use the sunpeak inspector to toggle inline, fullscreen, and PiP locally without deploying or using a paid host account. For automated tests, pass displayMode to inspector.renderTool so your CI suite covers each display mode, theme, and target host.

How do I request a display mode change from my MCP App?

With sunpeak, use useDisplayMode() to read the current mode and useRequestDisplayMode() to ask the host to switch modes. Check availableModes before showing controls, and tie requests to user interactions. The host may return a different mode than the one you requested.