Rearrange the panel's parts
The one-liner renders the default composition. To change what the panel holds, render a root with the parts you want as its children. Every container with no children renders its own default, so you only spell out the level you change.
A root lays its children out in a row: Threads, the thread list in a column of its own, and Main, the column that holds the header, the conversation, the composer and the footer. Leave Threads out and Main takes the whole width.
The five panels below run in the example’s panel playground, examples/app/components/panel-playground.tsx.
Start from the one-liner
Section titled “Start from the one-liner”<AssistedPanel mode="floating" threads models={models} />This is the default composition. Every prop it takes is a root prop, so the rest of this page can keep it.
Spell out the top level
Section titled “Spell out the top level”Render a root with Main and its three containers. Each renders its default, so this panel looks like the one-liner, opened in the bottom-left corner:
<AssistedPanel.Floating defaultPosition="bottom-left"> <AssistedPanel.Main> <AssistedPanel.Main> <AssistedPanel.Header /> <AssistedPanel.Conversation /> <AssistedPanel.Composer /> </AssistedPanel.Main> </AssistedPanel.Main></AssistedPanel.Floating>Leave a part out and it is gone. Reorder them and they move.
Put the threads beside the conversation
Section titled “Put the threads beside the conversation”Threads is the thread list in a column before Main, for a panel wide enough to show both. The one-liner places it with threads="side":
<AssistedPanel.Embedded threads="side" models={models} /> <AssistedPanel.Main>Spelled out, the same panel is a root with the two columns:
<AssistedPanel.Embedded models={models}> <AssistedPanel.Threads /> <AssistedPanel.Main /></AssistedPanel.Main></AssistedPanel.Embedded>Write your own header
Section titled “Write your own header”Give Header children and it renders exactly those. This sheet names the shop’s assistant, keeps the devtools and Close, and puts the thread select in a row of its own:
<AssistedPanel.Sheet> <AssistedPanel.Main> <AssistedPanel.Header> <AssistedPanel.Icon> <ShopLogo /> </AssistedPanel.Icon> <AssistedPanel.Title>Shop assistant</AssistedPanel.Title> <AssistedPanel.Devtools> <AssistedDevtoolsPanel /> </AssistedPanel.Devtools> <AssistedPanel.Close /> </AssistedPanel.Header> <AssistedPanel.ThreadSelect /> <AssistedPanel.Conversation /> <AssistedPanel.Composer /> </AssistedPanel.Main></AssistedPanel.Sheet>Add the data parts and trim the composer
Section titled “Add the data parts and trim the composer”Any part may sit in any container under a root. This embedded panel shows the context window in its header and footer, swaps the conversation for settings, and keeps three parts of the composer:
<AssistedPanel.Embedded models={models}> <AssistedPanel.Main> <AssistedPanel.Header> <AssistedPanel.Title /> <AssistedPanel.ContextDisplay /> <AssistedPanel.SettingsToggle /> </AssistedPanel.Header> <AssistedPanel.SettingsPanel> <AssistedPanel.ContextBreakdown /> <AssistedPanel.QuotaBanner used={42} limit={50} unit="messages" resetsIn="3h" upgradeLabel="Upgrade" /> </AssistedPanel.SettingsPanel> <AssistedPanel.Conversation> <AssistedPanel.ConversationSearch /> <AssistedPanel.Messages components={{ AssistantMessage: Mine }} /> <AssistedPanel.ScrollToBottom /> </AssistedPanel.Conversation> <AssistedPanel.Composer> <AssistedPanel.Input /> <AssistedPanel.ModelSelector /> <AssistedPanel.Send /> </AssistedPanel.Composer> <AssistedPanel.Footer> <AssistedPanel.ContextDisplay variant="bar" className="flex-1" /> </AssistedPanel.Footer> </AssistedPanel.Main></AssistedPanel.Embedded>Messages takes components for what happens inside a message. Mine is the example’s own assistant message, built from MessagePrimitive:
function Mine() { return ( <MessagePrimitive.Root className="rounded-lg border-s-2 border-teal-600 bg-teal-50 px-3 py-2 text-sm"> <MessagePrimitive.Parts /> </MessagePrimitive.Root> );}Use your own buttons and trigger
Section titled “Use your own buttons and trigger”A button part with asChild renders your element and keeps its behavior. This floating panel opens a thread drawer from the header with the host’s icon buttons, and opens only from a trigger the host places:
<> <AssistedPanel.Floating launcher={false}> <AssistedPanel.Main> <AssistedPanel.Header> <AssistedPanel.ThreadDrawerToggle asChild> <IconButton icon={PanelLeft} /> </AssistedPanel.ThreadDrawerToggle> <AssistedPanel.ThreadTitle /> <AssistedPanel.NewThread asChild> <IconButton icon={Plus} /> </AssistedPanel.NewThread> <AssistedPanel.Close /> </AssistedPanel.Header> <AssistedPanel.ThreadDrawer /> <AssistedPanel.Conversation /> <AssistedPanel.Composer /> </AssistedPanel.Main> </AssistedPanel.Floating> <nav className="fixed start-1/2 bottom-6 z-40 -translate-x-1/2"> <AssistedPanel.Trigger asChild> <Button>Help</Button> </AssistedPanel.Trigger> </nav></>IconButton is the example’s own button. asChild hands it the part’s onClick, aria-label and aria-pressed.
Rules of the parts
Section titled “Rules of the parts”- Render parts inside a root. The root holds the panel’s state: open, the picked model, the drawer, the search and the settings.
- A root is a row of
ThreadsandMain. The header, the conversation, the composer and the footer go inMain. - A container with no children renders its default. With children, it renders only those.
- Parts that have nothing to show render nothing:
ModelSelectorwithoutmodels,Devtoolswithout devtools,Footerwithout children. Triggeris the one part that may sit outside a root, anywhere underAssistedProvider.
Each group’s parts, props and default are on its page under Components. To replace a part with your own, see Make your own part.