Model selector
A <aparte-model-selector> web component that lets the user pick an AI provider and model — a grouped
dropdown built on core’s <aparte-select>, for the BYOK (Bring Your Own Key) pattern.
npm install @aparte/plugin-model-selector @aparte/core@aparte/core is the only peer dependency. Importing the package registers the element as a side
effect:
import '@aparte/plugin-model-selector';<aparte-model-selector auto-select persist searchable></aparte-model-selector>Each registered provider becomes an <aparte-optgroup>; a single provider renders a flat list.
| Attribute | Effect |
|---|---|
auto-select | Select the first available model on mount |
persist | Write the selection back to the resolved config |
searchable | Enable search in the dropdown |
placeholder | Override the placeholder (else the active locale string) |
disabled | Disable the picker; inside an <aparte-composer> it also follows the composer’s disabled |
It fires aparte-model-change with { providerId, modelId, previousProviderId, previousModelId }.
The selector reads providers from the nearest instance config (via attachConfig), falling back to the
global aparteGlobalConfig — so multi-chat pages each drive their own model list.
Where to put it
Section titled “Where to put it”In the composer’s bottom row — that is what the row is for, and it is one element:
<aparte-composer-toolbar> <aparte-model-selector style="margin-inline-start: auto"></aparte-model-selector></aparte-composer-toolbar>margin-inline-start: auto pushes it to the end of the row; drop it and the selector sits
at the start. In the four wrappers the same thing goes through one toolbar slot — see
The composer toolbar.
Typed in your framework
Section titled “Typed in your framework”The element is typed by this package, not by the framework wrappers, through one subpath per framework. Import that subpath once, anywhere in your app, and the tag is checked like any other: an unknown attribute or a wrong value type is a compile error.
Nothing to import for types — the tag is in HTMLElementTagNameMap as soon as the plugin
itself is imported, and its event is typed through HTMLElementEventMap.
<aparte-model-selector persist searchable placeholder="Pick a model"></aparte-model-selector>import '@aparte/plugin-model-selector/react';<aparte-model-selector persist="" searchable="" placeholder="Pick a model" />import '@aparte/plugin-model-selector/vue';<aparte-model-selector persist="" searchable="" placeholder="Pick a model" />import '@aparte/plugin-model-selector/svelte';<aparte-model-selector persist="" searchable="" placeholder="Pick a model" />A directive rather than a type, because Angular’s template compiler needs a class
claiming the selector — and the directive is what turns [persist] into a real binding.
import { AparteModelSelectorDirective } from '@aparte/plugin-model-selector/angular';// @Component({ imports: [AparteModelSelectorDirective], … })<aparte-model-selector [persist]="true" [searchable]="true" (modelChange)="use($event.modelId)" />Outside Angular a presence attribute is '' to set and null to remove, never false —
see the rule.
Events are typed through the DOM, because @aparte/core augments HTMLElementEventMap
with aparte-model-change.
react, vue, svelte and @angular/core are all optional peer dependencies, so
you carry only the one you use — and the three template bindings ship no runtime at all.
Gating the composer until a model is picked
Section titled “Gating the composer until a model is picked”The model list loads asynchronously, so there’s a window where the chat is mounted but no model is
selected yet. Opt in to block sending (and grey out <aparte-composer>) until one is:
import { aparteGlobalConfig } from '@aparte/core';
aparteGlobalConfig.setRequireModelSelection(true);The composer re-enables automatically once auto-select (or the user) picks a model. Off by default, so
single-model or backend-driven setups that never select a model are unaffected.
The <aparte-model-selector> element
Section titled “The <aparte-model-selector> element”Generated from the plugin’s own custom-elements manifest — the same file that feeds editor autocomplete when you install the package.
Example
<!-- Mount it in the composer's toolbar; it reads the models the config already knows. --><aparte-composer-toolbar> <aparte-model-selector searchable placeholder="Pick a model"></aparte-model-selector></aparte-composer-toolbar>Attributes
| Attribute | Description |
|---|---|
persist | Writes the selection back through the config, so it survives a reload. |
auto-select | Selects the first model as soon as one is available. |
searchable | Adds the dropdown’s filter field. |
placeholder | Overrides the text shown while nothing is selected. |
disabled | Disables the picker. Inside an <aparte-composer> it also follows the composer’s own disabled, so a disabled composer does not leave its model picker operable. |
Properties
| Property | Type | Description |
|---|---|---|
providerId (readonly) | string | null | Current provider ID. |
modelId (readonly) | string | null | Current model ID. |
Methods
| Method | Description |
|---|---|
aparteConfigChanged(next: AparteConfig): void | The boundary above us appeared or changed: move the subscription and reload, because a different config means different providers and a different selection. See AparteConfigAware. The element’s own per-instance tests passed before this existed only because they mount the boundary FIRST — the one ordering no wrapper produces. |
setSelection(providerId: string, modelId: string): void | Programmatically set the selection. |
Events
| Event | Type | Description |
|---|---|---|
aparte-model-change | CustomEvent<AparteModelChangeEventDetail> | The provider or the model changed; carries both ids. |