Suggestions
<aparte-suggestions>
Class: AparteSuggestions
Prompt starters — a row of suggested prompts a reader clicks instead of typing.
Every chat product opens on three or four of these, and the example app used to
hand-roll them: four <button class="chip">, a click handler, a CSS recipe of its
own. This element is that pattern done once, wearing the button recipe.
A click goes THROUGH the composer — setValue() then submit() — never a synthetic
aparte-send. The composer’s submit() is where every gate lives (disabled, already
streaming, requireModelSelection), and a chip that bypassed them once sent a
request with an empty model id while the composer was visibly greyed out. So the
element needs a composer: the nearest <aparte-composer> ancestor, else the one
serving the chat named by target, else the first one in the document.
Tier (a) of ratified decision #8: core honours the click alone, so it is live by
default. aparte-suggestion fires first and is cancelable — preventDefault()
leaves the composer untouched, for an app that wants the prompt for itself.
It declares no custom property of its own: the gap comes from the global
--aparte-space-* tokens and the chips from the aparte-btn recipe, so it inherits
a theme rather than exposing knobs to re-set.
Example
Section titled “Example”<!-- The starters sit above the input, inside the composer; a click fills and sends. --><aparte-composer> <aparte-suggestions empty-only suggestions='["What is aparté?", {"label": "Write a haiku", "prompt": "Write a haiku about web components."}]'> </aparte-suggestions> <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>Attributes
Section titled “Attributes”| Attribute | Description |
|---|---|
suggestions | The starters, as a JSON array: strings, or { "label", "prompt" } objects when the visible label and the sent text differ. The suggestions PROPERTY takes the same shape without the JSON. |
target | The id of the <aparte-chat> whose composer should receive the click, when the element is not inside that composer. |
empty-only | Shows the row only while the conversation it serves is empty: hidden (hidden) once a message is in its transcript or on its way — a thread being loaded counts — and shown again when the transcript is cleared, by a new chat for instance. The composer’s send hides it at once, before its message lands. The element sets and lifts hidden itself and never lifts one you set. With no transcript to read — a composer outside any chat — the first send hides it until the attribute is removed. |
mode | send (default): the click fills the composer and submits. fill: the click fills the composer and focuses it, so the reader edits first. |
data-empty | Reflected BY the element while it has no suggestion to show; the stylesheet hides it then. Read-only, do not set it yourself. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
suggestions | AparteSuggestion[] | Takes the array, or the JSON string the attribute documents. Both, because both arrive: React 19 and Svelte assign the PROPERTY whenever the element has one of that name, so <aparte-suggestions suggestions='[…]'> — the documented spelling, typed valid by both wrappers — reached this setter as a string, Array.isArray said no, and the row rendered nothing while the attribute (and so attributeChangedCallback) was never written. |
Events
Section titled “Events”| Event | Type | Description |
|---|---|---|
aparte-suggestion | CustomEvent<AparteSuggestionEventDetail> | A starter was clicked. Bubbles, and is cancelable: preventDefault() stops the composer from being filled or submitted. |
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-suggestions empty-only=""></aparte-suggestions>el.addEventListener('aparte-suggestion', (e) => use(e.detail));<aparte-suggestions empty-only=""></aparte-suggestions>The aparte-* tags are typed JSX intrinsics as soon as you import from @aparte/react. A presence attribute takes '', never true — React stringifies it, and empty-only={false} would render empty-only="false", which hasAttribute reads as on. Events reach you by ref, typed through the DOM.
<template> <aparte-suggestions empty-only="" @aparte-suggestion="(e) => use(e.detail)" ></aparte-suggestions></template>Declared through Vue’s GlobalComponents, so vue-tsc checks the tag in any template. A presence attribute takes '' to set and null to remove, never false.
<aparte-suggestions empty-only="" on:aparte-suggestion={(e) => use(e.detail)}></aparte-suggestions>Declared through SvelteHTMLElements, so svelte-check covers the attributes and the on: handlers. A presence attribute takes '', never false.
import { AparteSuggestionsDirective } from '@aparte/angular';<aparte-suggestions [emptyOnly]="true" (suggestion)="use($event)"></aparte-suggestions>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.