Put controls under the composer
The row under the composer, for a mode picker, a model selector or a counter — in plain HTML and in each framework — and the slot above it for a banner.
On this page
<aparte-composer placeholder="Ask anything…">
<div class="aparte-composer-shell">
<div class="aparte-composer-row">
<aparte-composer-input></aparte-composer-input>
<aparte-composer-send></aparte-composer-send>
</div>
<!-- The bottom row, laid out in DOM order. An action is an icon button that only emits
aparte-action-click: what it does is yours. -->
<aparte-composer-toolbar>
<aparte-composer-action icon="tool" label="Use tools" action-id="tools"></aparte-composer-action>
<aparte-composer-action icon="image" label="Generate an image" action-id="image"></aparte-composer-action>
<!-- From @aparte/plugin-model-selector: lists the models your providers declare.
margin-inline-start: auto pushes it, and whatever follows, to the end of the row. -->
<aparte-model-selector auto-select persist style="margin-inline-start: auto"></aparte-model-selector>
</aparte-composer-toolbar>
</div>
</aparte-composer>The toolbar
Section titled “The toolbar”<aparte-chat>
<aparte-chat-viewport></aparte-chat-viewport>
<aparte-elicitation></aparte-elicitation>
<aparte-composer>
<div class="aparte-composer-shell">
<div class="aparte-composer-row">
<aparte-composer-input></aparte-composer-input>
<aparte-composer-send></aparte-composer-send>
</div>
<aparte-composer-toolbar>
<my-mode-picker></my-mode-picker>
<aparte-model-selector persist style="margin-inline-start: auto"></aparte-model-selector>
</aparte-composer-toolbar>
</div>
</aparte-composer>
</aparte-chat><AparteChat
messages={chat.messages}
onMessagesChange={chat.setMessages}
toolbar={<>
<ModePicker value={mode} onChange={setMode} />
<aparte-model-selector persist="" style={{ marginInlineStart: 'auto' }} />
</>}
/><AparteChat :messages="chat.messages.value" @messages-change="chat.onMessagesChange">
<template #toolbar>
<ModePicker v-model="mode" />
<aparte-model-selector persist style="margin-inline-start: auto" />
</template>
</AparteChat><AparteChat messages={$messages} on:messagesChange={handleMessagesChange}>
<svelte:fragment slot="toolbar">
<ModePicker bind:value={mode} />
<aparte-model-selector persist style="margin-inline-start: auto"></aparte-model-selector>
</svelte:fragment>
</AparteChat><aparte-chat [messages]="messages" (messagesChange)="messages = $event">
<app-mode-picker slot="toolbar"></app-mode-picker>
<aparte-model-selector slot="toolbar" persist style="margin-inline-start: auto"></aparte-model-selector>
</aparte-chat><aparte-composer-toolbar> is the row under the input. Its controls sit
in the order you write them, and margin-inline-start: auto pushes one, with everything after it,
to the end — on the right, or on the left in a right-to-left language. An empty toolbar draws
nothing. The mode picker stands for a control of your own.
The default chat has no toolbar. In plain HTML, write the whole chat: the message list, the
<aparte-elicitation> panel where questions and approvals appear, and the
composer. An <aparte-chat> with no message list inside replaces its children with the default
chat, toolbar and all. The framework packages draw the row from their toolbar slot; in Angular,
each node you project carries slot="toolbar" itself. The slot belongs to the default composer,
so a composer of your own, put in through the composer slot, writes its own
<aparte-composer-toolbar>.
<aparte-model-selector> comes from @aparte/plugin-model-selector, and draws nothing until that
package is imported. Its /react, /vue and /svelte entries type the tag, and /angular exports
AparteModelSelectorDirective for a standalone component’s imports; persist makes its pick the
model the next message goes to. The
model selector and the approval mode
are two controls made for this row.
Above the composer
Section titled “Above the composer”<aparte-chat>
<aparte-chat-viewport></aparte-chat-viewport>
<p class="my-notice">Replies can be wrong. Check what matters.</p>
<aparte-composer>
<div class="aparte-composer-shell">
<div class="aparte-composer-row">
<aparte-composer-input></aparte-composer-input>
<aparte-composer-send></aparte-composer-send>
</div>
</div>
</aparte-composer>
</aparte-chat><AparteChat
messages={chat.messages}
onMessagesChange={chat.setMessages}
aboveComposer={<p className="my-notice">Replies can be wrong. Check what matters.</p>}
/><AparteChat :messages="chat.messages.value" @messages-change="chat.onMessagesChange">
<template #above-composer>
<p class="my-notice">Replies can be wrong. Check what matters.</p>
</template>
</AparteChat><AparteChat messages={$messages} on:messagesChange={handleMessagesChange}>
<p slot="above-composer" class="my-notice">Replies can be wrong. Check what matters.</p>
</AparteChat><aparte-chat [messages]="messages" (messagesChange)="messages = $event">
<p slot="above-composer" class="my-notice">Replies can be wrong. Check what matters.</p>
</aparte-chat>Between the messages and the composer goes a banner, a row of suggestions or a notice. In plain
HTML it is one more child of the chat, before the composer; the framework packages take it as
aboveComposer in React and the above-composer slot elsewhere. The
Wrapper surface lists every slot in each framework’s syntax.