RRenDS v0.14.1

Composite

Select Hybrid

A custom-styled dropdown for choosing one option from a list. Renders a trigger button and a popover list using the native Popover API where supported. Keyboard-accessible by default — typeahead, arrow keys, Home/End, Escape — and fully WAI-ARIA listbox compliant.

About

Overview

Use a Select when the options need richer rendering than a native <select> can offer — icons, descriptions, group separators, custom layouts. For plain text options under ~10 items in a form, prefer the native element via Form Field; the platform's behavior is hard to beat for accessibility and mobile pickers.

The trigger is a button, not an input. Selects don't accept typed input; they show a list and let the user pick. If you need free-text + suggestions, use Combobox instead.

Parts

Anatomy

A Select has three parts in the DOM: the trigger that's always visible, the listbox content that floats on open, and the items inside.

Assembled

1Container

<ren-select> wrapper. Holds trigger + content. Owns selection state and exposes a name/value API for forms.

2Trigger

.ren-select-trigger button with aria-haspopup="listbox". Shows the selected value or a placeholder. Click or Enter opens the list.

3Content

.ren-select-content with role="listbox". Floats on open via the Popover API. Closes on Escape, click outside, or selection.

4Item

.ren-select-item with role="option" and data-value. Optional data-highlighted for keyboard focus, aria-selected for the active choice.

Live

Demo

Click the trigger to open. Use Up/Down to navigate, Enter to select, Escape to close.

Argentina
Brazil
Chile
Mexico
United States
<ren-select name="country" placeholder="Select a country">
  <button type="button" class="ren-select-trigger" data-select-trigger aria-label="Country">
    <span class="ren-select-placeholder">Select a country</span>
    <span class="ren-select-icon" aria-hidden="true"><!-- chevron SVG --></span>
  </button>
  <div class="ren-select-content" data-select-content role="listbox" popover>
    <div class="ren-select-item" data-select-item data-value="ar">Argentina</div>
    <div class="ren-select-item" data-select-item data-value="br">Brazil</div>
    <div class="ren-select-item" data-select-item data-value="cl">Chile</div>
    <div class="ren-select-item" data-select-item data-value="mx">Mexico</div>
    <div class="ren-select-item" data-select-item data-value="us">United States</div>
  </div>
</ren-select>

Shapes

Variants

Sizes

Three sizes via size="sm|md|lg" on <ren-select> — generates .ren-select-sm, -md (default), or -lg. The trigger height matches the matching .ren-input size so selects line up with text fields in the same form.

With icon

Each .ren-select-item can hold any markup — an icon, a description, a badge. The component just routes selection by data-value.

With description

Add a secondary line per item with .ren-select-item-description. Useful for Plan pickers (name + price) or Locale pickers (name + native script).

Disabled

Add disabled on the trigger to lock the whole field. aria-disabled on individual .ren-select-item elements skips them in keyboard navigation.

Reference

API

CSS classes

ClassEffect
.ren-selectWrapper. Establishes the relative positioning context for the popover.
.ren-select-triggerThe button users see. Should be a real <button type="button">. Holds aria-haspopup="listbox" and aria-expanded.
.ren-select-valueThe slot where the selected option's display text appears.
.ren-select-placeholderReplaces .ren-select-value styling when nothing is selected — muted color.
.ren-select-iconThe chevron at the trigger's end. Rotates 180° while the listbox is open.
.ren-select-contentThe floating list. Use with popover attribute and role="listbox". Auto-positioned by the component.
.ren-select-itemOne option. Use with role="option" and a data-value. aria-selected="true" marks the chosen one.
.ren-select-sm / -lgSize modifiers. Default trigger is medium (44 px touch target).

Web Component attributes

AttributeTypeDefaultNotes
namestring—Form field name. Submitted via a hidden input so the value travels with the form.
valuestring—Initial selected value. Must match a data-value on one of the items.
placeholderstring"Select an option"Trigger text when nothing is selected.
placement"top" | "right" | "bottom" | "left""bottom"Preferred side for the listbox. Reflected to data-side; may flip when viewport space requires it.
size"sm" | "md" | "lg""md"Visual size variant.
disabledbooleanfalsePrevents opening. Adds aria-disabled.

JavaScript API

MemberDescription
valueGetter / setter. Reads or assigns the selected value. Setting triggers ren-change.
selectedItemGetter. The currently selected .ren-select-item element (or null).
open() / close()Programmatically toggle the listbox.
isOpenBoolean getter. True while the listbox is visible.

Events

EventDetail
ren-changeFires when the selection changes. event.detail: { value, item }.
ren-open / ren-closeFire when the listbox opens or closes. No detail.

Inclusive by default

Accessibility

Implements the WAI-ARIA Listbox pattern via the trigger + popover combination.

Keyboard

Space / EnterOn the trigger: opens the listbox. On a list item: selects it and closes.
↑ / ↓Move highlight through the items. Wraps at the ends.
Home / EndJump to the first or last item.
Type to filterTypeahead — types build a buffer that highlights the first matching item. Buffer clears after 500 ms idle.
EscCloses the listbox without changing the selection. Focus returns to the trigger.

Labelling

The component gives the trigger role="combobox", and a combobox takes its name from the author, not from its contents — the placeholder text inside the button is not an accessible name. Always set aria-label on the trigger, or point aria-labelledby at your own visible label. The demo above uses aria-label="Country".

Avoid putting too many items in one Select. Past ~15, switch to a Combobox with search. Typeahead helps but doesn't scale to hundreds.

Patterns

Examples

Inside a Form Field

<ren-field> <label>Country</label> <ren-select name="country" placeholder="Select your country"> <button type="button" class="ren-select-trigger" data-select-trigger aria-label="Country"> <span class="ren-select-placeholder">Select your country</span> <span class="ren-select-icon" aria-hidden="true"><!-- chevron SVG --></span> </button> <div class="ren-select-content" data-select-content role="listbox" popover> <div class="ren-select-item" data-select-item data-value="ar">Argentina</div> <div class="ren-select-item" data-select-item data-value="br">Brazil</div> </div> </ren-select> </ren-field>

React to selection

document.querySelector('ren-select') .addEventListener('ren-change', (e) => { console.log('Selected', e.detail.value); updatePreview(e.detail.value); });

Items with icons + descriptions

<div class="ren-select-item" data-value="basic"> <span class="ren-select-item-icon"><!-- icon SVG --></span> <span> <strong>Basic</strong> <span class="ren-select-item-description">$9 per month</span> </span> </div>