Rettangoli Docs
Select

A controlled option-picker component for single-choice selection.

Quickstart

Use options as data source and listen to value-change.

Fruit
<rtgl-view d="v" g="sm" w="320">
  <rtgl-text c="mu">Fruit</rtgl-text>
  <rtgl-select id="fruit-select" placeholder="Choose fruit" w="f"></rtgl-select>
</rtgl-view>

<script>
  const select = document.getElementById("fruit-select");

  select.options = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
    { value: "orange", label: "Orange" },
  ];

  select.addEventListener("value-change", (e) => {
    console.log(e.detail.value);
  });

  select.render();
</script>

Core Decisions

Choose Data Binding Style

Intent Recommended
Define options list set options as a property
Control selected item initially set selectedValue property
Placeholder text placeholder attribute or property

Choose Clear Behavior

Intent Recommended
Allow clear icon default
Lock selection until another option is chosen no-clear

Choose Add-Option UX

Intent Recommended
Standard select menu omit addOption
Add action row at bottom set addOption property

Choose Search Behavior

Intent Recommended
Small option list omit searchable
Filter long option lists by label searchable

API

Name Attribute / Property Type Default
Placeholder placeholder string Select an option
Selected Value selected-value / selectedValue any -
Options options (property) { type?: "item" | "section" | "separator", label?: string, value?: any, icon?: string, shortcut?: string, suffixText?: string, testId?: string }[] []
No Clear no-clear boolean off
Add Option addOption (property) { label?: string } -
Disabled disabled boolean false
Searchable searchable boolean false
Search Placeholder search-placeholder / searchPlaceholder string Search options
Empty Search Label empty-search-label / emptySearchLabel string No matching options
Trigger Width w number, %, xs-xl, f, CSS length/value content-based
Trigger Margin m, mt, mr, mb, ml, mv, mh xs, sm, md, lg, xl -

Events

Event Detail Description
value-change { value, label, index, item } Fires when selection changes or is cleared
add-option-click {} Fires when add-option row is clicked

Options

Define selectable entries through the options property.

Behavior & precedence

  • type: "item" is the default row type.
  • Item rows should include label and value.
  • type: "section" renders a non-selectable header row.
  • type: "separator" renders a non-selectable divider row.
  • value can be primitive or object.
  • icon renders a leading icon in the menu and selected trigger.
  • shortcut renders right-side trailing text and takes precedence over suffixText.
  • suffixText renders right-side trailing text when shortcut is not provided.
  • testId is optional and useful for testing.
  • When searchable is enabled, the popover filters item rows by case-insensitive label match.
<rtgl-select id="position-select" placeholder="Select position"></rtgl-select>

<script>
  const select = document.getElementById("position-select");
  select.options = [
    { value: { x: 0, y: 0 }, label: "Top Left" },
    { value: { x: 0.5, y: 0.5 }, label: "Center" },
    { value: { x: 1, y: 1 }, label: "Bottom Right" },
  ];
  select.render();
</script>
<rtgl-select id="command-select" placeholder="Choose command"></rtgl-select>

<script>
  const select = document.getElementById("command-select");
  select.options = [
    { type: "section", label: "Clipboard" },
    { value: "copy", label: "Copy", icon: "text", shortcut: "Cmd+C" },
    { value: "paste", label: "Paste", icon: "threeDots", shortcut: "Cmd+V" },
    { type: "separator" },
    { type: "section", label: "Inspector" },
    { value: "info", label: "Details", icon: "info", suffixText: "Beta" },
  ];
  select.selectedValue = "copy";
  select.render();
</script>

Searchable

Use searchable for longer option lists. Search filters by option label; selected trigger display still resolves from the full options list.

<rtgl-select id="searchable-role" searchable search-placeholder="Search roles"></rtgl-select>

<script>
  const select = document.getElementById("searchable-role");
  select.options = [
    { type: "section", label: "Product" },
    { value: "designer", label: "Designer" },
    { value: "researcher", label: "Researcher" },
    { type: "separator" },
    { type: "section", label: "Engineering" },
    { value: "frontend", label: "Frontend Engineer" },
    { value: "backend", label: "Backend Engineer" },
  ];
  select.render();
</script>

Selected Value

Set initial/current selection via selectedValue or selected-value.

Behavior & precedence

  • If selectedValue matches an option, that label is shown.
  • Matching options also surface their icon and trailing text in the trigger.
  • If it does not match, placeholder label is shown.
  • Clearing emits value-change with value: undefined.
<rtgl-select id="status-select" selected-value="active"></rtgl-select>

<script>
  const select = document.getElementById("status-select");
  select.options = [
    { value: "active", label: "Active" },
    { value: "paused", label: "Paused" },
  ];
  select.render();
</script>

No Clear

Use no-clear when clear affordance must be hidden.

<rtgl-view d="v" g="md" w="320">
  <rtgl-select id="clear-on"></rtgl-select>
  <rtgl-select id="clear-off" no-clear></rtgl-select>
</rtgl-view>

<script>
  const options = [
    { value: "1", label: "Option 1" },
    { value: "2", label: "Option 2" },
  ];

  const clearOn = document.getElementById("clear-on");
  clearOn.selectedValue = "2";
  clearOn.options = options;
  clearOn.render();

  const clearOff = document.getElementById("clear-off");
  clearOff.selectedValue = "2";
  clearOff.options = options;
  clearOff.render();
</script>

Add Option

Use addOption to render an extra action row at the bottom of the menu.

Behavior & precedence

  • addOption = {} shows a default add row.
  • addOption = { label: "..." } customizes add row label.
  • Clicking that row emits add-option-click.
<rtgl-select id="tag-select" placeholder="Select or add tag"></rtgl-select>

<script>
  const select = document.getElementById("tag-select");
  select.options = [
    { value: "bug", label: "Bug" },
    { value: "feature", label: "Feature" },
  ];
  select.addOption = { label: "Add new tag" };
  select.addEventListener("add-option-click", () => {
    console.log("Add option clicked");
  });
  select.render();
</script>

Disabled

Use disabled to make the select non-interactive.

Behavior & precedence

  • Trigger cannot be opened while disabled.
  • Clear icon and add-option row are hidden while disabled.
  • Programmatic value updates still work.
<rtgl-select id="disabled-select" disabled></rtgl-select>

<script>
  const select = document.getElementById("disabled-select");
  select.options = [
    { value: "1", label: "Option 1" },
    { value: "2", label: "Option 2" },
  ];
  select.selectedValue = "2";
  select.render();
</script>

Form Field

rtgl-form passes search props through to select fields.

- name: role
  type: select
  label: Role
  searchable: true
  searchPlaceholder: Search roles
  options:
    - label: Admin
      value: admin
    - label: Editor
      value: editor
    - label: Viewer
      value: viewer

Events Example

<rtgl-select id="country-select" placeholder="Country"></rtgl-select>
<script>
  const select = document.getElementById("country-select");
  select.options = [
    { value: "us", label: "United States" },
    { value: "ca", label: "Canada" },
  ];

  select.addEventListener("value-change", (e) => {
    console.log("value-change", e.detail);
  });

  select.addEventListener("add-option-click", () => {
    console.log("add-option-click");
  });

  select.render();
</script>