Skip to main content Home About the Design SystemRoadmap OverviewDesignersDevelopers OverviewColorGridIconographyInteractionsSpacingTypography Overview Global colorBox shadowTypographyBorderOpacitySpaceLengthIconBreakpointsMedia queries All elements Accordion Alert Announcement Audio player Avatar Back to top Badge Blockquote Breadcrumb Button group Button Card Chip Code block Call to action Dialog Disclosure Footer Health index Icon Jump links Menu dropdown Navigation link Navigation (primary) Navigation (secondary) Navigation (vertical) Pagination PopoverPlanned Progress stepper Readtime Scheme toggle Select Site status Skeleton Skip link Spinner Statistic Subnavigation Surface Switch Table Tabs Tag Tile Timestamp Tooltip Video embed OverviewColor PalettesCustomizingDevelopers All PatternsAccordionAlertCall to ActionCardFilterFormLink with iconLogo wallSearch barSticky bannerSticky cardTabsTagTile All Personalization PatternsAnnouncement FundamentalsAccessibility toolsAssistive technologiesCI/CDContentContributorsDesignDevelopmentManual testingResourcesScreen readers Design/code status Release notes Get support

Select

OverviewStyleGuidelinesCodeAccessibilityDemos
SelectColor ContextDynamic OptionsEventsMethods SimpleMethodsOption DescriptionsOption GroupOption IconsRequiredStatesTooltipSelectColor ContextDynamic OptionsEventsMethods SimpleMethodsOption DescriptionsOption GroupOption IconsRequiredStatesTooltip

Select

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<label for="my-select">
  Products
</label>
<rh-select id="my-select" placeholder="Select an item">
  <rh-option>Device Edge</rh-option>
  <rh-option>JBoss Web Server</rh-option>
  <rh-option>OpenShift</rh-option>
  <rh-option disabled="">Red Hat Lightspeed</rh-option>
  <rh-option>Quay</rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="my-select">Products</label>
  <Select id="my-select" placeholder="Select an item">
    <Option>Device Edge</Option>
    <Option>JBoss Web Server</Option>
    <Option>OpenShift</Option>
    <Option disabled>Red Hat Lightspeed</Option>
    <Option>Quay</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Color Context

import '@rhds/elements/lib/elements/rh-context-demo/rh-context-demo.js';
import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<rh-context-demo>
  <label for="select-1">
    Label
  </label>
  <rh-select id="select-1" placeholder="Select an item">
    <rh-option>Ansible Lightspeed</rh-option>
    <rh-option set="ui" icon="document">Certificate System</rh-option>
    <rh-option>Connectivity Link</rh-option>
    <rh-option>Device Edge</rh-option>
    <rh-option>
      Directory Server
      <span slot="description">Centralized directory service</span>
    </rh-option>
    <rh-option-group label="RHEL">
      <rh-option>Enterprise Linux</rh-option>
      <rh-option>Enterprise Linux Lightspeed</rh-option>
    </rh-option-group>
    <rh-option>JBoss Web Server</rh-option>
  </rh-select>
</rh-context-demo>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { ContextDemo } from "@rhds/elements/react/rh-context-demo/rh-context-demo.js";
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { OptionGroup } from "@rhds/elements/react/rh-option-group/rh-option-group.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <ContextDemo>
    <label htmlFor="select-1">Label</label>
    <Select id="select-1" placeholder="Select an item">
      <Option>Ansible Lightspeed</Option>
      <Option set="ui" icon="document">Certificate System</Option>
      <Option>Connectivity Link</Option>
      <Option>Device Edge</Option>
      <Option>
        Directory Server
        <span slot="description">Centralized directory service</span>
      </Option>
      <OptionGroup label="RHEL">
        <Option>Enterprise Linux</Option>
        <Option>Enterprise Linux Lightspeed</Option>
      </OptionGroup>
      <Option>JBoss Web Server</Option>
    </Select>
  </ContextDemo>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Dynamic Options

import '@rhds/elements/rh-select/rh-select.js';

await customElements.whenDefined('rh-select');
const select = document.getElementById('my-select');
const group = document.getElementById('dynamic-group');
const addBtn = document.getElementById('add-option');
const removeBtn = document.getElementById('remove-option');
const addGroupBtn = document.getElementById('add-group-option');
const removeGroupBtn = document.getElementById('remove-group-option');
let optionCount = 0;

/** Direct child <rh-option> elements of the select (not inside a group). */
function getTopLevelOptions() {
  return Array.from(select.children).filter(
    (el) => el instanceof HTMLElement && el.localName === 'rh-option',
  );
}

/** Direct child <rh-option> elements inside the option group. */
function getGroupOptions() {
  return Array.from(group.children).filter(
    (el) => el instanceof HTMLElement && el.localName === 'rh-option',
  );
}

/**
 * rh-select rebuilds its option list when its default slot fires `slotchange`.
 * Adding/removing <rh-option> inside <rh-option-group> does not change that slot,
 * so we re-insert the group at the same spot to trigger a refresh.
 */
function refreshSelectAfterGroupMutation() {
  const next = group.nextSibling;
  group.remove();
  if (next) {
    select.insertBefore(group, next);
  } else {
    select.appendChild(group);
  }
}

/**
 * Adds a new rh-option as a direct child of the select (sibling to the group).
 */
function addOption() {
  const option = document.createElement('rh-option');
  optionCount += 1;
  option.textContent = `New top-level option ${optionCount}`;
  option.value = `new-root-${optionCount}`;
  select.appendChild(option);
  updateRemoveButtonState();
}

/**
 * Removes the last top-level rh-option from the select.
 */
function removeOption() {
  const options = getTopLevelOptions();
  if (options.length > 1) {
    options[options.length - 1].remove();
    updateRemoveButtonState();
  }
}

/**
 * Appends a new rh-option inside the existing rh-option-group.
 */
function addGroupOption() {
  const option = document.createElement('rh-option');
  optionCount += 1;
  option.textContent = `New grouped option ${optionCount}`;
  option.value = `new-group-${optionCount}`;
  group.appendChild(option);
  refreshSelectAfterGroupMutation();
  updateGroupRemoveButtonState();
}

/**
 * Removes the last rh-option from inside the group.
 */
function removeGroupOption() {
  const options = getGroupOptions();
  if (options.length > 1) {
    options[options.length - 1].remove();
    refreshSelectAfterGroupMutation();
    updateGroupRemoveButtonState();
  }
}

/**
 * Disable top-level remove when only one top-level option remains.
 */
function updateRemoveButtonState() {
  removeBtn.disabled = getTopLevelOptions().length <= 1;
}

/**
 * Disable group remove when only one option remains in the group.
 */
function updateGroupRemoveButtonState() {
  removeGroupBtn.disabled = getGroupOptions().length <= 1;
}

addBtn.addEventListener('click', addOption);
removeBtn.addEventListener('click', removeOption);
addGroupBtn.addEventListener('click', addGroupOption);
removeGroupBtn.addEventListener('click', removeGroupOption);

updateRemoveButtonState();
updateGroupRemoveButtonState();
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}

.button-group {
  display: flex;
  flex-direction: column;
  gap: var(--rh-space-sm, 8px);
  margin-inline: 20px;
  margin-block-start: var(--rh-space-lg, 16px);
}

.button-group-label {
  font-family: var(--rh-font-family-body-text);
  font-size: var(--rh-font-size-body-text-sm, 0.875rem);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  color: var(--rh-color-text-secondary, #6a6e73);
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--rh-space-sm, 8px);
}

.button-row button {
  font-family: var(--rh-font-family-body-text);
  padding: var(--rh-space-sm, 8px) var(--rh-space-md, 16px);
}

.button-row button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
<label for="my-select">
  Products
</label>
<rh-select id="my-select" placeholder="Select an item">
  <rh-option>Device Edge</rh-option>
  <rh-option>JBoss Web Server</rh-option>
  <rh-option-group id="dynamic-group" label="Dynamic group" disabled="">
    <rh-option>OpenShift</rh-option>
    <rh-option disabled="">Red Hat Lightspeed</rh-option>
    <rh-option>Quay</rh-option>
  </rh-option-group>
</rh-select>

<div class="button-group">
  <span class="button-group-label">Top-level options</span>
  <div class="button-row">
    <button type="button" id="add-option">Add option</button>
    <button type="button" id="remove-option">Remove option</button>
  </div>
</div>

<div class="button-group">
  <span class="button-group-label">Inside “Dynamic group”</span>
  <div class="button-row">
    <button type="button" id="add-group-option">Add option to group</button>
    <button type="button" id="remove-group-option">Remove from group</button>
  </div>
</div>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { OptionGroup } from "@rhds/elements/react/rh-option-group/rh-option-group.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="my-select">Products</label>
  <Select id="my-select" placeholder="Select an item">
    <Option>Device Edge</Option>
    <Option>JBoss Web Server</Option>
    <OptionGroup id="dynamic-group" label="Dynamic group" disabled>
      <Option>OpenShift</Option>
      <Option disabled>Red Hat Lightspeed</Option>
      <Option>Quay</Option>
    </OptionGroup>
  </Select>
  <div className="button-group">
    <span className="button-group-label">Top-level options</span>
    <div className="button-row">
      <button type="button" id="add-option">Add option</button>
      <button type="button" id="remove-option">Remove option</button>
    </div>
  </div>
  <div className="button-group">
    <span className="button-group-label">Inside “Dynamic group”</span>
    <div className="button-row">
      <button type="button" id="add-group-option">Add option to group</button>
      <button type="button" id="remove-group-option">Remove from group</button>
    </div>
  </div>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Events

import '@rhds/elements/rh-select/rh-select.js';

const getSelect = document.querySelector('#select-8');
const getForm = document.querySelector('form');
const events = [];
getForm.addEventListener('submit', event => event.preventDefault());
const onSelectEvent = (event) => {
  events.push(event.type);
  getForm.elements.events.value = events.join(', ');
};
getSelect.addEventListener('change', onSelectEvent);
getSelect.addEventListener('open', onSelectEvent);
getSelect.addEventListener('close', onSelectEvent);
label,
rh-select,
.container {
  margin-inline: 20px;
  margin-block-end: var(--rh-space-md, 8px);
}

label,
rh-select {
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<form>
  <label for="select-8">
    Events
  </label>
  <rh-select id="select-8" placeholder="Select an item">
    <rh-option>Red Hat Lightspeed</rh-option>
    <rh-option disabled="">OpenShift</rh-option>
    <rh-option>Quay</rh-option>
  </rh-select>

  <p class="container">
    A change event is fired whenever the page loads or a selection is made.
  </p>

  <fieldset class="container">
    <legend>Events Fired</legend>
    <output name="events">No events yet</output>
  </fieldset>
</form>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <form>
    <label htmlFor="select-8">Events</label>
    <Select id="select-8" placeholder="Select an item">
      <Option>Red Hat Lightspeed</Option>
      <Option disabled>OpenShift</Option>
      <Option>Quay</Option>
    </Select>
    <p className="container">A change event is fired whenever the page loads or a selection is made.</p>
    <fieldset className="container">
      <legend>Events Fired</legend>
      <output name="events">No events yet</output>
    </fieldset>
  </form>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Methods Simple

import '@rhds/elements/rh-select/rh-select.js';

const select = document.querySelector('rh-select');
const [toggleBtn, showBtn, hideBtn] = document.querySelectorAll('button');

await customElements.whenDefined('rh-select');
await select.updateComplete; // Wait for select to be fully rendered

showBtn.addEventListener('click', () => select.show());
hideBtn.addEventListener('click', () => select.hide());
toggleBtn.addEventListener('click', () => select.toggle());
button {
  &:first-child {
    margin-block: var(--rh-space-md, 8px);
    margin-inline-start: 20px;
  }
}

label,
rh-select  {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<button>Toggle</button>
<button>Show</button>
<button>Hide</button>

<label for="select-simple">
  Methods (simple)
</label>
<rh-select id="select-simple" placeholder="Select an item">
  <rh-option>OpenShift</rh-option>
  <rh-option>Quay</rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <button>Toggle</button>
  <button>Show</button>
  <button>Hide</button>
  <label htmlFor="select-simple">Methods (simple)</label>
  <Select id="select-simple" placeholder="Select an item">
    <Option>OpenShift</Option>
    <Option>Quay</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Methods

import '@rhds/elements/rh-button/rh-button.js';
import '@rhds/elements/rh-select/rh-select.js';

const select = document.querySelector('rh-select');
const [toggleBtn, showBtn, hideBtn] = document.querySelectorAll('rh-button');

await customElements.whenDefined('rh-select');
await select.updateComplete; // Wait for select to be fully rendered

showBtn.addEventListener('click', () => select.show());
hideBtn.addEventListener('click', () => select.hide());
toggleBtn.addEventListener('click', () => select.toggle());
rh-button {
  &:first-child {
    margin-block: var(--rh-space-md, 8px);
    margin-inline-start: 20px;
  }
}
  
label,
rh-select  {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<rh-button variant="primary">Toggle</rh-button>
<rh-button variant="secondary">Show</rh-button>
<rh-button variant="secondary">Hide</rh-button>

<label for="select-9">
  Methods
</label>
<rh-select id="select-9" placeholder="Select an item">
  <rh-option>OpenShift</rh-option>
  <rh-option>Quay</rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Button } from "@rhds/elements/react/rh-button/rh-button.js";
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Button variant="primary">Toggle</Button>
  <Button variant="secondary">Show</Button>
  <Button variant="secondary">Hide</Button>
  <label htmlFor="select-9">Methods</label>
  <Select id="select-9" placeholder="Select an item">
    <Option>OpenShift</Option>
    <Option>Quay</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Option Descriptions

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<label for="select-3">
  With option descriptions
</label>
<rh-select id="select-3" placeholder="Select a country">
  <rh-option label="Canada" value="ca" description="Longest coastline of any country"></rh-option>
  <rh-option label="Germany" value="de" description="Worlds third largest importer and exporter"></rh-option>
  <hr>
  <rh-option label="India" value="in" description="Seventh largest country by area"></rh-option>
  <rh-option>
    Israel
    <span slot="description">Slotted content instead of attributes</span>
  </rh-option>
  <rh-option label="United States" value="us" description="50 states" disabled="">
  </rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="select-3">With option descriptions</label>
  <Select id="select-3" placeholder="Select a country">
    <Option label="Canada" value="ca" description="Longest coastline of any country" />
    <Option label="Germany" value="de" description="Worlds third largest importer and exporter" />
    <hr />
    <Option label="India" value="in" description="Seventh largest country by area" />
    <Option>
      Israel
      <span slot="description">Slotted content instead of attributes</span>
    </Option>
    <Option label="United States" value="us" description="50 states" disabled />
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Option Group

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<label for="select-4">
  With option group
</label>
<rh-select id="select-4" placeholder="Select an item">
  <rh-option>
    3scale API Management
  </rh-option>
  <rh-option disabled="">
    AI Inference Server
  </rh-option>
  <rh-option-group label="Ansible">
    <rh-option>
      Ansible Automation Platform
    </rh-option>
    <rh-option>
      Ansible Lightspeed
    </rh-option>
  </rh-option-group>
  <rh-option>
    Certificate System
  </rh-option>
  <rh-option>
    Connectivity Link
  </rh-option>
  <rh-option-group disabled="" label="Developer Tools">
    <rh-option>
      Developer Hub
    </rh-option>
    <rh-option>
      Device Edge
    </rh-option>
    <rh-option>
      Directory Server
    </rh-option>
  </rh-option-group>
  <rh-option-group label="RHEL">
    <rh-option>
      Enterprise Linux
    </rh-option>
    <rh-option>
      Enterprise Linux Lightspeed
    </rh-option>
  </rh-option-group>
  <rh-option>
    High performance computing portfolio
  </rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom.css">
<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { OptionGroup } from "@rhds/elements/react/rh-option-group/rh-option-group.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="select-4">With option group</label>
  <Select id="select-4" placeholder="Select an item">
    <Option>3scale API Management</Option>
    <Option disabled>AI Inference Server</Option>
    <OptionGroup label="Ansible">
      <Option>Ansible Automation Platform</Option>
      <Option>Ansible Lightspeed</Option>
    </OptionGroup>
    <Option>Certificate System</Option>
    <Option>Connectivity Link</Option>
    <OptionGroup disabled label="Developer Tools">
      <Option>Developer Hub</Option>
      <Option>Device Edge</Option>
      <Option>Directory Server</Option>
    </OptionGroup>
    <OptionGroup label="RHEL">
      <Option>Enterprise Linux</Option>
      <Option>Enterprise Linux Lightspeed</Option>
    </OptionGroup>
    <Option>High performance computing portfolio</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom.css" />
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Option Icons

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}
<label for="select-2">
  With option icons
</label>
<rh-select id="select-2" placeholder="Select an item">
  <rh-option icon-set="ui" icon="document">
    3scale API Management
  </rh-option>
  <rh-option disabled="" icon-set="ui" icon="document">
    AI Inference Server
  </rh-option>
  <rh-option>
    Ansible Automation Platform
  </rh-option>
  <rh-option icon-set="ui" icon="document">
    Ansible Lightspeed
  </rh-option>
  <hr>
  <rh-option icon-set="ui" icon="document">
    Certificate System
  </rh-option>
  <rh-option icon-set="ui" icon="document">
    Connectivity Link
  </rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="select-2">With option icons</label>
  <Select id="select-2" placeholder="Select an item">
    <Option icon-set="ui" icon="document">3scale API Management</Option>
    <Option disabled icon-set="ui" icon="document">AI Inference Server</Option>
    <Option>Ansible Automation Platform</Option>
    <Option icon-set="ui" icon="document">Ansible Lightspeed</Option>
    <hr />
    <Option icon-set="ui" icon="document">Certificate System</Option>
    <Option icon-set="ui" icon="document">Connectivity Link</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Required

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select,
button {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}

button {
  margin-block-start: var(--rh-space-md, 8px);
}

.required {
  color: var(--rh-color-status-danger);
}
<form>
  <label for="my-select">
    Products <span class="required" aria-label="Required field">*</span>
  </label>
  <rh-select required="" id="my-select" name="products" placeholder="Select an item">
    <rh-option>Device Edge</rh-option>
    <rh-option>JBoss Web Server</rh-option>
    <rh-option>OpenShift</rh-option>
    <rh-option disabled="">Red Hat Lightspeed</rh-option>
    <rh-option>Quay</rh-option>
  </rh-select>
  <button type="submit">Submit</button>
</form>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <form>
    <label htmlFor="my-select">
      Products
      <span className="required" aria-label="Required field">*</span>
    </label>
    <Select required id="my-select" name="products" placeholder="Select an item">
      <Option>Device Edge</Option>
      <Option>JBoss Web Server</Option>
      <Option>OpenShift</Option>
      <Option disabled>Red Hat Lightspeed</Option>
      <Option>Quay</Option>
    </Select>
    <button type="submit">Submit</button>
  </form>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

States

import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline: 20px;
  max-inline-size: 320px;
}

label {
  display: block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}

rh-select {
  margin-block-end: var(--rh-space-xl, 24px);
}
<label for="select-5">
  Success
</label>
<rh-select id="select-5" placeholder="Select an item" state="success" help-text="Sucess message">
  <rh-option>3scale API Management</rh-option>
  <rh-option>Ansible Automation Platform</rh-option>
  <rh-option>Ansible Lightspeed</rh-option>
</rh-select>

<label for="select-6">
  Warning
</label>
<rh-select id="select-6" placeholder="Select an item" state="warning" help-text="Warning message">
  <rh-option>Certificate System</rh-option>
  <rh-option>Connectivity Link</rh-option>
  <rh-option>Data Grid</rh-option>
</rh-select>

<label for="select-7">
  Danger
</label>
<rh-select id="select-7" placeholder="Select an item" state="danger" help-text="Danger message">
  <rh-option>Developer Hub</rh-option>
  <rh-option>Device Edge</rh-option>
  <rh-option>Directory Server</rh-option>
</rh-select>

<label for="select-8">
  Label
</label>
<rh-select id="select-8" placeholder="Select an item" help-text="Help text">
  <rh-option>JBoss Web Server</rh-option>
  <rh-option>OpenShift</rh-option>
  <rh-option>Red Hat Lightspeed</rh-option>
</rh-select>

<label for="select-9">
  Slotted help text
</label>
<rh-select id="select-9" placeholder="Select an item">
  <rh-option>Quay</rh-option>
  <rh-option>Runtimes</rh-option>
  <rh-option>Satellite</rh-option>
  <p slot="help-text">Slotted help text</p>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="select-5">Success</label>
  <Select id="select-5" placeholder="Select an item" state="success" help-text="Sucess message">
    <Option>3scale API Management</Option>
    <Option>Ansible Automation Platform</Option>
    <Option>Ansible Lightspeed</Option>
  </Select>
  <label htmlFor="select-6">Warning</label>
  <Select id="select-6" placeholder="Select an item" state="warning" help-text="Warning message">
    <Option>Certificate System</Option>
    <Option>Connectivity Link</Option>
    <Option>Data Grid</Option>
  </Select>
  <label htmlFor="select-7">Danger</label>
  <Select id="select-7" placeholder="Select an item" state="danger" help-text="Danger message">
    <Option>Developer Hub</Option>
    <Option>Device Edge</Option>
    <Option>Directory Server</Option>
  </Select>
  <label htmlFor="select-8">Label</label>
  <Select id="select-8" placeholder="Select an item" help-text="Help text">
    <Option>JBoss Web Server</Option>
    <Option>OpenShift</Option>
    <Option>Red Hat Lightspeed</Option>
  </Select>
  <label htmlFor="select-9">Slotted help text</label>
  <Select id="select-9" placeholder="Select an item">
    <Option>Quay</Option>
    <Option>Runtimes</Option>
    <Option>Satellite</Option>
    <p slot="help-text">Slotted help text</p>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);

Tooltip

import '@rhds/elements/rh-tooltip/rh-tooltip.js';
import '@rhds/elements/rh-select/rh-select.js';
label,
rh-select {
  margin-inline-start: 20px;
  max-inline-size: 320px;
}

label {
  display: inline-block;
  font-family: var(--rh-font-family-body-text);
  font-weight: var(--rh-font-weight-body-text-medium, 500);
  margin-block: var(--rh-space-md, 8px);
}

rh-tooltip {
  font-weight: var(--rh-font-weight-body-text-regular, 400);
}

button {
  align-items: center;
  background-color: transparent;
  border: 0;
  display: flex;
  justify-content: center;
  min-block-size: var(--rh-length-xl, 24px);
  min-inline-size: var(--rh-length-xl, 24px);
  padding: 0;

  &:hover {
    color: var(--rh-color-interactive-primary-hover);
  }

  &:focus-visible {
    outline-color: var(--rh-color-border-interactive);
  }
}
<label for="select-1">
  Red Hat Products
</label>
<rh-tooltip>
  <button>
    <rh-icon set="ui" icon="question-mark-circle" accessible-label="More information"></rh-icon>
  </button>
  <span slot="content">Extra helpful information</span>
</rh-tooltip>
<rh-select id="select-1" placeholder="Select an item">
  <rh-option>3scale API Management</rh-option>
  <rh-option>AI Inference Server</rh-option>
  <rh-option>Ansible Automation Platform</rh-option>
  <rh-option>Ansible Lightspeed</rh-option>
  <rh-option>Certificate System</rh-option>
  <rh-option>Connectivity Link</rh-option>
  <rh-option>Data Grid</rh-option>
</rh-select>

<link rel="stylesheet" href="../rh-select-lightdom-shim.css">
import { Icon } from "@rhds/elements/react/rh-icon/rh-icon.js";
import { Option } from "@rhds/elements/react/rh-option/rh-option.js";
import { Select } from "@rhds/elements/react/rh-select/rh-select.js";
import { Tooltip } from "@rhds/elements/react/rh-tooltip/rh-tooltip.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <label htmlFor="select-1">Red Hat Products</label>
  <Tooltip>
    <button>
      <Icon set="ui" icon="question-mark-circle" accessible-label="More information" />
    </button>
    <span slot="content">Extra helpful information</span>
  </Tooltip>
  <Select id="select-1" placeholder="Select an item">
    <Option>3scale API Management</Option>
    <Option>AI Inference Server</Option>
    <Option>Ansible Automation Platform</Option>
    <Option>Ansible Lightspeed</Option>
    <Option>Certificate System</Option>
    <Option>Connectivity Link</Option>
    <Option>Data Grid</Option>
  </Select>
  <link rel="stylesheet" href="../rh-select-lightdom-shim.css" />
);
© 2026 Red Hat Deploys by Netlify