Components
ElvixLanguages

ElvixLanguages

Single-frame wizard for spoken languages and CEFR proficiency, capped at 8 with tap-to-edit and delete-confirm.

app/account/languages/page.tsx
"use client";
import { ElvixLanguages } from "@elvix.is/sdk/react";
export default function LanguagesPane() {
return (
<ElvixLanguages
onChange={(languages) => {
// Optional: mirror to local state for sibling panes. The SDK already persisted.
console.log("languages now:", languages.length);
}}
onResult={(r) => {
if (!r.ok) return console.warn(r.error, r.message);
// r.count is the new total (0 to 8).
}}
/>
);
}

Props

PropTypeRequiredDefaultDescription
heightnumberoptionalmin(540px, 66dvh)Fixed pixel height for the <ElvixCard> frame.
minHeightnumberoptional340Minimum pixel height when height is unset.
maxHeightnumberoptional700Maximum pixel height when height is unset.
widthnumber | stringoptional"100%"Frame width. Numbers are pixels; strings pass through as CSS.
onChange(languages: LanguageRecord[]) => voidoptionalFires whenever the underlying record set changes (add, edit level, delete). Receives the full list.
onResult(r: ElvixLanguagesResult) => voidoptionalTerminal save callback. Success payload is minimal ({ ok: true, count }); failure is { ok: false, error, message? }.

The picker hides itself the moment the user hits 8 entries. If you see the add affordance disappear in QA, that is the cap doing its job, not a bug. To free a slot, the user taps an existing row and uses the in-frame delete-confirm.

onResult.count is intentionally the only success field, so the host never receives the full language list as a side-channel. Subscribe to onChange if you need the records for sibling panes.

Related