Components

SelectList

SelectList shows a scrolling list of text options and marks the chosen one with a check mark. The core renders the rows from your array of strings, so a list of thousands of options costs about as much as the visible rows, and no JS runs while scrolling.

ui-select-list.tsx Edit in Playground Open in new tab
// SelectList: 500 options, one chosen; controlled and uncontrolled.
import { mount, signal, Text, View } from "nsh";
import { Button, SelectList } from "nsh/ui/mobile";

const cities = Array.from({ length: 500 }, (_, i) => `City ${i + 1}`);
const sizes = ["Small", "Medium", "Large"];

function App() {
  const city = signal<number | null>(2);
  const lastSize = signal("none");
  return (
    <View style={{ flex: 1, backgroundColor: "#f5f5f5", padding: 16, paddingTop: 24, gap: 12 }}>
      <Text style={{ fontSize: 22, fontWeight: "700" }}>SelectList</Text>
      <Text style={{ color: "#737373" }}>{`Controlled: ${city() === null ? "none" : cities[city()!]}`}</Text>
      <Button
        variant="secondary"
        title="Choose the next city"
        onPress={() => city.set(city() === null ? 0 : (city()! + 1) % cities.length)}
      />
      <View style={{ flex: 1, borderRadius: 12, overflow: "hidden" }}>
        <SelectList options={cities} value={city()} onSelect={(i) => city.set(i)} />
      </View>
      <Text style={{ color: "#737373" }}>{`Uncontrolled, last chosen: ${lastSize()}`}</Text>
      <View style={{ height: 144, borderRadius: 12, overflow: "hidden" }}>
        <SelectList options={sizes} onSelect={(i) => lastSize.set(sizes[i])} />
      </View>
    </View>
  );
}

mount(App);
import { SelectList } from "nsh/ui/mobile";

#Usage

import { mount, signal, Text, View } from "nsh";
import { SelectList } from "nsh/ui/mobile";

const languages = ["English", "Deutsch", "Español", "Français", "日本語", "中文"];

function App() {
  const chosen = signal<number | null>(0);
  return (
    <View style={{ flex: 1, paddingTop: 48 }}>
      <Text style={{ padding: 16 }}>{`Language: ${chosen() === null ? "none" : languages[chosen()!]}`}</Text>
      <SelectList options={languages} value={chosen()} onSelect={(i) => chosen.set(i)} />
    </View>
  );
}

mount(App);

SelectList fills its parent (flex: 1). To show it inside a scroll view or next to other content, give it a parent with a fixed height:

<View style={{ height: 240, borderRadius: 12, overflow: "hidden" }}>
  <SelectList options={cities} onSelect={(i) => console.log(cities[i])} />
</View>

#Controlled and uncontrolled

  • Controlled: pass value (the chosen index, or null for none) and update it in onSelect. The check mark follows value. If you do not update value, the check mark does not move.
  • Uncontrolled: leave out value. The list keeps the choice itself and moves the check mark on each press. onSelect still reports each choice.

onSelect is called on every press, also when the user presses the option that is already chosen.

#Rows

Each row is at least 48 pt tall, with 16 pt horizontal padding, the option’s text, and a check mark (✓) at the end of the chosen row. Rows are separated by 1 pt dividers and highlighted while pressed.

#Props

PropTypeDefaultDescription
optionsstring[]requiredThe options, in order.
valuenumber | nullnone (uncontrolled)The index of the chosen option, when the app controls it.
class, classList, style, testID, onLayout, refApplied to the list’s root view.

#Events

EventPayloadWhen
onSelectnumber: the option’s indexThe user pressed an option.

#Theming

PartTheme key
Row backgroundbackground
Row while pressedlist.active.background
Textforeground
Check markprimary.background
Dividersborder

See Theming.

#Accessibility

Each row has the button role, and the chosen row is reported as selected. Screen readers read the option’s text.

  • ListView: rows you render yourself.
  • Sheet: show a SelectList in a bottom sheet as a picker.
  • ActionSheet: a short list of actions in a system dialog.