Composer
Installation
npx @mielui/svelte add composeryarn dlx @mielui/svelte add composerbunx @mielui/svelte add composerUsage
The theme setting chrome.borders chooses "single" or "double" framing. Single is the default. Single removes the extra frame while preserving content padding, composition, and inset variants.
Bind the prompt value on Root and handle submission with onSubmit. Composer waits for async handlers and shows the submitting state until they finish. Submit names its icon Send, Queue message, or Stop response to match the current action.
If submission rejects, Composer preserves the prompt and shows labels.error. Use onError to report the failure, then retry with the same submit button. If you set status="error" yourself, your application must clear it.
<script lang="ts">
import * as Composer from '@mielui/svelte/components/composer';
let value = $state('');
async function send(prompt: string) {
const response = await fetch('/api/messages', {
method: 'POST',
body: prompt
});
if (!response.ok) {
throw new Error(response.statusText);
}
value = '';
}
</script>
<Composer.Root bind:value onSubmit={send}>
<Composer.Header>
<!-- Optional context above the input -->
</Composer.Header>
<Composer.Input placeholder="Ask anything..." />
<Composer.Toolbar>
<Composer.Actions>
<!-- Attachment, model or permission controls -->
</Composer.Actions>
<Composer.Submit />
</Composer.Toolbar>
<Composer.Footer>
<!-- Optional strip under the writing surface -->
</Composer.Footer>
</Composer.Root>By default, โต submits and โงโต inserts a new line. Set submitOnEnter=false on Input when Enter should always create a new line.
Glass surface
Composer follows the theme's surface setting. Glass frosts the frame and keeps the writing surface on a more opaque fill. Set surface="glass" or surface="solid" on Root to force one regardless of the theme.
Submission and cancellation
Return a promise from onSubmit to keep the submit control pending until your request settles. Reject it to preserve the prompt and display labels.error. Use controlled status="submitting" or generating for a stoppable response. onStop must cancel your request or timer; it does not cancel application work automatically. The examples below include a real stop action and a failure you can retry.
Examples
Agent prompt
A composer with attachments, permission and model pickers, dictation, and a footer action.
Idle
Enter sends. Shift + Enter adds a line.
Submitting
Send the prompt, then stop it before the demo finishes.
Error
Attachments
Wrap Composer.Root in Attachment.Root so files can be dropped anywhere on the
composer. Place Attachment.List variant="chip" above Composer.Root, inside Attachment.Root, to show a scrolling row of chips
outside the frame. The list disappears when there are no files.
- brief.pdf Ready
cloud.svg Ready
- lead-list.xlsx Ready
- meeting-notes.md Ready
Toolbar placement
The composer is a recessed frame holding a raised writing surface. The toolbar joins
the input on that surface by default. Set variant="inset"
to keep the input on its own surface with the toolbar on the frame under it. Toolbar
controls are ghost buttons and triggers. Outline ones render as flat pills at the
same height. Send is the one filled primary pill, and it turns neutral while it
stops a response.
Footer
Composer.Footer is a strip on the frame under the writing surface, for a hint, connected apps, or a setting that applies to the whole message. The input and toolbar stay joined above it. Its text is muted and its controls use the small control height. It takes no space while it is empty.
Empty messages and the disabled state
Submit is disabled while the input is empty. Set allowEmpty on Root when a message can be only attachments, so it can be sent with no text. disabled on Root turns off the input and the button together.
Submit changes job as the conversation moves. While a response is generating and the input is empty it stops the response, and with text typed it queues the next message. labels.stop and labels.queue on Root are its accessible names in those two states, and labels.sending names it while onSubmit is pending. Its onclick runs first, and calling preventDefault() there cancels the stop.
Sent 0 times
Parts
Input and Submit accept element to bind the textarea and the button.
Root, Header, Toolbar, Actions, Submit and Footer render their children and accept class and style like any element.
Labels
Built-in text is English by default. Pass a labels object of type ComposerLabels to Composer.Root to translate the input placeholder and accessible name, the toolbar name, the four names of Submit, and the message shown when submitting fails. Every key is optional; omitted keys keep their default. A placeholder or aria-label set directly on Input or Toolbar wins over labels.
<script lang="ts">
import * as Composer from '@mielui/svelte/components/composer';
import type { ComposerLabels } from '@mielui/svelte/components/composer';
let value = $state('');
const labels: ComposerLabels = {
placeholder: 'รcrivez ร lโagentโฆ',
input: 'Message',
toolbar: 'Actions du message',
send: 'Envoyer',
queue: 'Mettre en file',
stop: 'Arrรชter la rรฉponse',
sending: 'Envoi',
error: "Le message n'a pas pu รชtre envoyรฉ."
};
function send() {
value = '';
}
</script>
<Composer.Root bind:value {labels} onSubmit={send}>
<Composer.Input />
<Composer.Toolbar>
<Composer.Submit />
</Composer.Toolbar>
</Composer.Root>API reference
Composer.Root
Manages prompt submission.
labelsComposerLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
surface"solid" | "glass"Surface treatment. Omit it to inherit
--mielui-surfacefrom the theme.valueBindablestringMessage text. Bindable.
Default
''statusComposerStatusCurrent state of the composer, which sets what the submit control does.
Default
'idle'generatingbooleanWhether a response is being generated independently of submission state.
disabledbooleanPrevents interaction and dims the control.
Default
falseallowEmptybooleanAllows submitting with no text, for a message that is only attachments.
Default
falseonSubmitRequired(value: string, event: SubmitEvent) => void | Promise<void>Called with the text on submit. Return a promise to show progress until it settles.
onError((error: unknown) => void)Called with the error when
onSubmitrejects.onStop(() => void)Called when the stop control is pressed during a response.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
Composer.Actions
Groups composer actions.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
Composer.Footer
Holds a strip under the writing surface.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
Composer.Header
Holds chips above the input.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
Composer.Input
Accepts the prompt text.
submitOnEnterbooleanEnter submits and Shift+Enter adds a line. Set false to make Enter add a line.
Default
trueelementBindableHTMLTextAreaElementBindable reference to the DOM element.
classstringClasses added to the element.
Composer.Submit
Submits or stops the prompt.
childrenSnippet<[Readonly<{ action: ComposerSubmitAction; generating: boolean; empty: boolean; }>]>Content rendered inside.
elementBindableHTMLButtonElement | HTMLAnchorElementBindable reference to the DOM element.
onclick((event: MouseEvent) => void)Called when it is clicked or activated.
classstringClasses added to the element.
Composer.Toolbar
Groups composer controls.
variant"default" | "inset"insetputs the input on its own inset surface and the toolbar in the frame under it, like an inset Card. The default joins the toolbar to the input on one surface.Default
'default'classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
pnpm dlx @mielui/svelte add composer