RRenDS v0.13.0

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.

<ren-select name="country" placeholder="Select a country">
  <button class="ren-select-trigger">
    <span class="ren-select-value"></span>
    <span class="ren-select-icon">…</span>
  </button>
  <div class="ren-select-content" popover>
    <div class="ren-select-item" data-value="ar">Argentina</div>
    <div class="ren-select-item" data-value="br">Brazil</div>
    <div class="ren-select-item" data-value="cl">Chile</div>
    <div class="ren-select-item" data-value="mx">Mexico</div>
    <div class="ren-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
namestringForm field name. Submitted via a hidden input so the value travels with the form.
valuestringInitial 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

Wrap the Select inside a Form Field so the label, description and error get auto-wired. Or set aria-label directly on the trigger if there's no visible label.

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 class="ren-select-trigger"> <span class="ren-select-value"></span> <span class="ren-select-icon">…</span> </button> <div class="ren-select-content" popover> <div class="ren-select-item" data-value="ar">Argentina</div> <div class="ren-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>