Elicitation
<aparte-elicitation>
The default presenter for a request to the human. It renders nothing itself: it
registers as the presenter for the config governing its subtree, and mounts a panel
inside the nearest <aparte-composer> when something asks — a tool handler calling
requestUserInput, or core’s own approval gate.
It dispatches no events on purpose. A request is answered through the typed presenter
contract, not by listening for one; the aparte-tool-decision event this replaced
existed only because the buttons used to live in a segment renderer with no reference
to the client.
It has no children to project: connectedCallback sets
display: none, and the composer it presents in is found by walking UP from
this.parentElement — anything placed inside this element is only hidden with it.
So its position matters but its content does not: mount it anywhere inside the
<aparte-chat> whose questions it should answer.
Not the element to reach for when you want a question UI of your own shape. It is
one caller of setElicitationPresenter, and among presenters registered for the
same chat the most recent one wins — so an app with a framework-native presenter
registers that and does not mount this, and a second <aparte-elicitation> in one
chat is redundant rather than additive. It is also not usable outside a chat that
has an <aparte-composer>: with nowhere to mount a panel the request is REJECTED,
on purpose, rather than borrowed into another chat’s composer.
The panel it mounts is styled by @aparte/core/styles.css — the --aparte-elic-*
and --aparte-approval-* knobs below theme it. They are declared here rather than
on the composer because this presenter is what builds the panel; the composer only
lends it the slot.
Example
Section titled “Example”<!-- Renders nothing by itself: it registers as the presenter for its subtree, so a tool handler calling requestUserInput() gets its panel mounted in the composer. --><aparte-chat style="height: 20rem"> <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> </div> </aparte-composer></aparte-chat>
<script> // `aparte` is the `@aparte/core` module the frame exposes; in your app this line is // `import { requestUserInput } from '@aparte/core'`. A tool handler asks; the panel // mounts in the composer of the chat whose presenter this element is. aparte.requestUserInput({ message: 'Which environment should I deploy to?', schema: { type: 'enum', options: [ { value: 'staging', label: 'Staging', recommended: true }, { value: 'prod', label: 'Production', description: 'Live traffic' }, ], }, });</script>Methods
Section titled “Methods”| Method | Description |
|---|---|
aparteConfigChanged(next: AparteConfig, previous: AparteConfig): void | The boundary above us appeared, changed, or went away — move the registration with it. connectedCallback alone is not enough and cannot be: registering is a WRITE, and under all four wrappers it happens before attachConfig runs, so it lands on the global singleton. requestUserInput() then resolves the instance config, finds nothing, and rejects the request — the model hears the user refuse a question the user never saw. See AparteConfigAware. |
Theming
Section titled “Theming”Override any of these on :root, on a subtree, or on one instance — custom properties inherit downward. Some are this element’s own; others are site-wide tokens that also style it, and overriding one of those at :root moves everything that reads it. The full set is in the CSS variables reference.
<aparte-elicitation>
Section titled “<aparte-elicitation>”| Variable | Default | Description |
|---|---|---|
--aparte-elic-gap | var(--aparte-space-3) | Vertical gap between the panel’s rows (message, body, tabs). |
--aparte-elic-padding | var(--aparte-space-3) var(--aparte-space-2) | Padding inside the panel. |
--aparte-elic-max-height | 50vh | Cap on the panel’s height; its body scrolls, the panel does not. |
--aparte-elic-field-gap | var(--aparte-space-4) | Space and separator padding between two fields of an object schema. |
--aparte-elic-message-size | var(--aparte-font-size-base) | Font size of the question text at the top of the panel. |
--aparte-elic-title-size | var(--aparte-font-size-base) | Font size of a field’s title. |
--aparte-elic-desc-size | var(--aparte-font-size-sm) | Font size of a field’s description. |
--aparte-elic-option-padding | var(--aparte-space-4) var(--aparte-space-5) | Padding of one enum/boolean option row. |
--aparte-elic-option-radius | var(--aparte-radius-md) | Corner radius of an option row. |
--aparte-elic-option-title-size | var(--aparte-font-size-md) | Font size of an option’s label, and of the text inputs. |
--aparte-elic-option-desc-size | var(--aparte-font-size-sm) | Font size of an option’s secondary line. |
--aparte-elic-control-size | 15px | Size of the radio/checkbox control in an option row. |
--aparte-elic-input-radius | var(--aparte-radius-md) | Corner radius of the text inputs and of the Skip button. |
--aparte-elic-textarea-min-height | 64px | Minimum height of a multi-line string field. |
--aparte-elic-input-size | 0.85rem | Font size of the approval panel’s instruction field (the free-text note the user writes). |
--aparte-elic-skip-size | var(--aparte-font-size-md) | Font size of the corner “Skip” affordance (the decline). |
--aparte-elic-step-size | var(--aparte-font-size-sm) | Font size of a step tab, when the schema is asked one field at a time. |
--aparte-elic-step-padding | var(--aparte-space-2) var(--aparte-space-1) | Padding of a step tab. |
--aparte-elic-step-gap | var(--aparte-space-7) | Gap between step tabs. |
--aparte-elic-step-underline | 2px | Thickness of the current step’s underline (a tab, not a pill). |
--aparte-elic-dismiss-room | 72px | Space the tab rail and the question message keep clear for the corner escape. Widen it for a locale whose “Skip” word is wider. |
--aparte-approval-gap | 4px | Gap between the stacked options of an approval request. |
--aparte-approval-option-size | 0.85rem | Font size of an approval option button. |
--aparte-approval-option-padding | 8px 10px | Padding of an approval option button. |
--aparte-approval-option-radius | 8px | Corner radius of an approval option button. |
--aparte-approval-args-max-height | 8.5rem | Height cap of the arguments block before it scrolls. |
--aparte-approval-args-size | var(--aparte-font-size-sm) | Font size of the arguments block. |
In a framework
Section titled “In a framework”The element is the same object everywhere — the tag does not change. What changes is how an attribute is written and how an event reaches you.
<aparte-elicitation></aparte-elicitation><aparte-elicitation></aparte-elicitation>The aparte-* tags are typed JSX intrinsics as soon as you import from @aparte/react.
<template> <aparte-elicitation></aparte-elicitation></template>Declared through Vue’s GlobalComponents, so vue-tsc checks the tag in any template.
<aparte-elicitation></aparte-elicitation>Declared through SvelteHTMLElements, so svelte-check covers the attributes and the on: handlers.
import { AparteElicitationDirective } from '@aparte/angular';<aparte-elicitation></aparte-elicitation>A standalone directive whose selector IS the tag, so the real element sits in the template — @if, @for and content projection all reach it — and no CUSTOM_ELEMENTS_SCHEMA is needed.
Installation and the framework-specific traps: React · Vue · Svelte · Angular.