# Select

> Dropdown picker with search, multi-select, virtualization-ready items, and full keyboard nav.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://sisyphosui.com/docs/components/select

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { Select } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

export const Country = () => {
  const [value, setValue] = useState<string | number | null>("tr");
  return (
    <Select
      label="Country"
      value={value}
      onChange={setValue}
      searchable
      clearable
      options={[
        { value: "tr", label: "Türkiye" },
        { value: "us", label: "United States" },
      ]}
    />
  );
};
```

### Vue 3+

```vue
<script setup lang="ts">
import { ref } from "vue";
import { Select } from "@sisyphos-ui/vue";
const value = ref<string | number | null>("tr");
const options = [
  { value: "tr", label: "Türkiye" },
  { value: "us", label: "United States" },
];
</script>

<template>
  <Select label="Country" v-model="value" :searchable="true" :clearable="true" :options="options" />
</template>
```

### Angular 17+

```ts
import { Component, signal } from "@angular/core";
import { Select } from "@sisyphos-ui/angular";

@Component({
  selector: "app-country",
  standalone: true,
  imports: [Select],
  template: `
    <sui-select
      label="Country"
      [(value)]="value"
      [searchable]="true"
      [clearable]="true"
      [options]="options"
    />
  `,
})
export class CountryComponent {
  value = signal<string | number | null>("tr");
  options = [
    { value: "tr", label: "Türkiye" },
    { value: "us", label: "United States" },
  ];
}
```

## Examples

### Default

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

const FRAMEWORKS = [
  { label: "React",   value: "react" },
  { label: "Vue",     value: "vue" },
  { label: "Svelte",  value: "svelte" },
  { label: "Solid",   value: "solid" },
  { label: "Angular", value: "angular" },
];

export function Example() {
  const [value, setValue] = useState<string | number | null>(null);

  return (
    <div className="w-full max-w-xs">
      <Select
        label="Framework"
        placeholder="Pick one"
        options={FRAMEWORKS}
        value={value}
        onChange={setValue}
      />
    </div>
  );
}
```

### Multi select

Add `multiple` to allow multiple values; `value` becomes an array.

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

const FRAMEWORKS = [
  { label: "React",   value: "react" },
  { label: "Vue",     value: "vue" },
  { label: "Svelte",  value: "svelte" },
  { label: "Solid",   value: "solid" },
  { label: "Angular", value: "angular" },
];

export function Example() {
  const [value, setValue] = useState<(string | number)[]>(["react"]);

  return (
    <div className="w-full max-w-xs">
      <Select
        multiple
        label="Frameworks you know"
        placeholder="Pick some"
        options={FRAMEWORKS}
        value={value}
        onChange={setValue}
      />
    </div>
  );
}
```

### Searchable & clearable

`searchable` adds an input filter; `clearable` shows a clear button.

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

const COUNTRIES = [
  { value: "tr", label: "Türkiye" },
  { value: "us", label: "United States" },
  { value: "de", label: "Germany" },
  /* …many more… */
];

export function Example() {
  const [value, setValue] = useState<string | number | null>(null);

  return (
    <Select
      label="Country"
      placeholder="Search countries…"
      searchable
      clearable
      options={COUNTRIES}
      value={value}
      onChange={setValue}
    />
  );
}
```

### Clear button

Clearable for quick reset — keeps existing keyboard ergonomics.

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

const FRAMEWORKS = [
  { label: "React",   value: "react" },
  { label: "Vue",     value: "vue" },
  { label: "Svelte",  value: "svelte" },
  { label: "Solid",   value: "solid" },
  { label: "Angular", value: "angular" },
];

export function Example() {
  const [value, setValue] = useState<string | number | null>("react");

  return (
    <Select
      label="Framework"
      clearable
      options={FRAMEWORKS}
      value={value}
      onChange={setValue}
    />
  );
}
```

### Error state

Surface validation with `error` + `errorMessage`.

```tsx
import { Select } from "@sisyphos-ui/react";

const FRAMEWORKS = [
  { label: "React",   value: "react" },
  { label: "Vue",     value: "vue" },
  { label: "Svelte",  value: "svelte" },
];

export function Example() {
  return (
    <Select
      label="Framework"
      placeholder="Required"
      options={FRAMEWORKS}
      value={null}
      error
      errorMessage="Please pick a framework to continue."
    />
  );
}
```

### Infinite scroll

`loading`, `hasMore`, and `onLoadMore` enable server-driven pagination. Works with `searchable`.

```tsx
import { useState } from "react";
import { Select } from "@sisyphos-ui/react";

export function Example() {
  const [value, setValue] = useState<string | number | null>(null);
  const [options, setOptions] = useState(() =>
    Array.from({ length: 30 }, (_, i) => ({ value: i, label: `Item ${i + 1}` }))
  );
  const [hasMore, setHasMore] = useState(true);
  const [loading, setLoading] = useState(false);

  const loadMore = () => {
    if (loading || !hasMore) return;
    setLoading(true);
    setTimeout(() => {
      setOptions((prev) => [
        ...prev,
        ...Array.from({ length: 20 }, (_, i) => ({
          value: prev.length + i,
          label: `Item ${prev.length + i + 1}`,
        })),
      ]);
      setLoading(false);
      if (options.length + 20 >= 90) setHasMore(false);
    }, 600);
  };

  return (
    <Select
      label="Virtualized list"
      placeholder="Scroll to load more"
      options={options}
      searchable
      value={value}
      onChange={setValue}
      loading={loading}
      hasMore={hasMore}
      onLoadMore={loadMore}
    />
  );
}
```

<!-- exports: { "Select": "@sisyphos-ui/react" } -->