Skip to content

Select — usage examples ​

Not on npm yet

@rozie-ui/select is not yet on npm for any framework target — it is still in dogfooding across all six.

Select is designed to ship as six pre-compiled, per-framework packages from a single .rozie source, but none has published to npm yet. The snippets below show the idiomatic consumption code for each target's workspace build — for review, not yet installable.

Usage ​

tsx
// @rozie-ui/select-react is not yet published to npm — this shows the workspace build, for review only.
import { useState } from 'react';
import { Select } from '@rozie-ui/select-react';

export function Demo() {
  const [value, setValue] = useState<string | null>(null);
  const options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
  const groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
  return (
    <Select
      value={value}
      onValueChange={setValue}
      options={options}
      groups={groups}
      clearable
      placeholder="Pick a fruit…"
      // Custom option render via the renderOption render-prop (React's scoped
      // slots are props, not children); the equivalent form is
      // slots={{ option: ... }}.
      renderOption={({ option, active, selected }) => (
        <span className={selected ? 'selected' : active ? 'active' : undefined}>{option.label}</span>
      )}
    />
  );
}
vue
<!-- @rozie-ui/select-vue is not yet published to npm — this shows the workspace build, for review only. -->
<script setup lang="ts">
import { ref } from 'vue';
import Select from '@rozie-ui/select-vue';

const value = ref<string | null>(null);
const options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
const groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
</script>

<template>
  <Select v-model:value="value" :options="options" :groups="groups" clearable placeholder="Pick a fruit…">
    <template #option="{ option, active, selected }">
      <span :class="{ active, selected }">{{ option.label }}</span>
    </template>
  </Select>
</template>
svelte
<!-- @rozie-ui/select-svelte is not yet published to npm — this shows the workspace build, for review only. -->
<script lang="ts">
  import Select from '@rozie-ui/select-svelte';

  let value = $state<string | null>(null);
  const options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
  const groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
</script>

<Select bind:value {options} {groups} clearable placeholder="Pick a fruit…">
  {#snippet option({ option, active, selected })}
    <span class:active class:selected>{option.label}</span>
  {/snippet}
</Select>
ts
// @rozie-ui/select-angular is not yet published to npm — this shows the workspace build, for review only.
import { Component } from '@angular/core';
import { Select } from '@rozie-ui/select-angular';

@Component({
  selector: 'app-demo',
  standalone: true,
  imports: [Select],
  template: `
    <Select [(value)]="value" [options]="options" [groups]="groups" [clearable]="true" placeholder="Pick a fruit…">
      <ng-template #option let-option="option" let-selected="selected">
        <span [class.selected]="selected">{{ option.label }}</span>
      </ng-template>
    </Select>
  `,
})
export class DemoComponent {
  value: string | null = null;
  options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
  groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
}
tsx
// @rozie-ui/select-solid is not yet published to npm — this shows the workspace build, for review only.
import { createSignal } from 'solid-js';
import { Select } from '@rozie-ui/select-solid';

export function Demo() {
  const [value, setValue] = createSignal<string | null>(null);
  const options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
  const groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
  return (
    <Select
      value={value()}
      onValueChange={setValue}
      options={options}
      groups={groups}
      clearable
      placeholder="Pick a fruit…"
      // Custom option render via the optionSlot prop (Solid's scoped slots
      // are props, not children); the ctx fields are plain values, not
      // signal accessors. Sibling scoped slots follow the same pattern:
      // selectedSlot ({ selected, value }) and emptySlot ({ query }).
      optionSlot={({ option, selected }) => <span classList={{ selected }}>{option.label}</span>}
    />
  );
}
ts
// @rozie-ui/select-lit is not yet published to npm — this shows the workspace build, for review only.
import '@rozie-ui/select-lit';

// <rozie-select> is a custom element. Bind `options`/`value` as properties and
// listen for the `value-change` event to receive the new selection.
const el = document.querySelector('rozie-select');
el.options = [
    { label: 'Apple', value: 'apple', group: 'fruit' },
    { label: 'Banana', value: 'banana', group: 'fruit' },
    { label: 'Carrot', value: 'carrot', group: 'veg' },
  ];
el.groups = [
    { id: 'fruit', label: 'Fruit' },
    { id: 'veg', label: 'Vegetables' },
  ];
el.clearable = true;
el.addEventListener('value-change', (e) => {
  el.value = e.detail;
});

Imperative handle ​

Beyond props and events, Select exposes imperative methods (declared once in the .rozie source via $expose). Grab a handle through your framework's native ref mechanism and call them directly:

tsx
// @rozie-ui/select-react is not yet published to npm — this shows the workspace build, for review only.
import { useRef } from 'react';
import { Select, type SelectHandle } from '@rozie-ui/select-react';

const lb = useRef<SelectHandle>(null);
// <Select ref={lb} ... />
lb.current?.open();
lb.current?.clear();
vue
<!-- @rozie-ui/select-vue is not yet published to npm — this shows the workspace build, for review only. -->
<script setup>
import { ref } from 'vue';
const lb = ref();          // template ref
</script>

<template>
  <Select ref="lb" :options="options" />
  <button @click="lb.toggle()">Toggle</button>
</template>
svelte
<!-- @rozie-ui/select-svelte is not yet published to npm — this shows the workspace build, for review only. -->
<script>
  let lb;                  // component instance via bind:this
</script>

<Select bind:this={lb} {options} />
<button onclick={() => lb.open()}>Open</button>
ts
// @rozie-ui/select-angular is not yet published to npm — this shows the workspace build, for review only.
@Component({ /* ... */ })
export class DemoComponent {
  @ViewChild(Select) lb!: Select;   // or the viewChild() signal
  openIt() { this.lb.open(); }
  clearIt() { this.lb.clear(); }
}
tsx
// @rozie-ui/select-solid is not yet published to npm — this shows the workspace build, for review only.
import { Select, type SelectHandle } from '@rozie-ui/select-solid';

let handle: SelectHandle | undefined;
// The ref callback receives the HANDLE object (not the DOM node).
<Select ref={(h) => (handle = h)} options={options} />;
handle?.open();
ts
// @rozie-ui/select-lit is not yet published to npm — this shows the workspace build, for review only.
// The custom element IS the handle — exposed methods are public element
// methods. (focusControl, not focus — focus is the native HTMLElement method.)
const el = document.querySelector('rozie-select');
el.open();
el.focusControl();

See also ​

Pre-1.0 — APIs may change between minor versions.