NativeSelect

Native select element based on Input

PackageIcon

Usage

NativeSelect component supports Input and Input.Wrapper component features and all select element props. The NativeSelect documentation does not include all features supported by the component – see the Input documentation to learn about all available features.

Input description

Variant
Size
Radius
import { NativeSelect } from '@mantine/core';

function Demo() {
  return <NativeSelect label="Input label" description="Input description" data={['React', 'Angular', 'Vue']} />;
}

Loading state

Set loading prop to display a loading indicator. By default, the loader is displayed on the right side of the input. You can change the position with the loadingPosition prop to 'left' or 'right'. This is useful for async operations like API calls, searches, or validations:

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect
      label="Your favorite framework"
      data={['React', 'Angular', 'Vue', 'Svelte']}
      loading
    />
  );
}

Controlled

import { useState } from 'react';
import { NativeSelect } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState('');

  return (
    <NativeSelect
      value={value}
      onChange={(event) => setValue(event.currentTarget.value)}
      data={['React', 'Angular', 'Svelte', 'Vue']}
    />
  );
}

Uncontrolled

NativeSelect can be used with uncontrolled forms the same way as a native select element. Set the name attribute to include native select value in FormData object on form submission. To control the initial value in uncontrolled forms, use the defaultValue prop.

Example usage of uncontrolled NativeSelect with FormData:

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.currentTarget);
        console.log('Select value:', formData.get('framework'));
      }}
    >
      <NativeSelect
        label="Select a framework"
        name="framework"
        data={['React', 'Angular', 'Svelte', 'Vue']}
        defaultValue="React"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Adding options

NativeSelect allows passing options in two ways:

  • data prop array
  • children prop with option components

Note that if children is used, the data will be ignored.

data prop

The data prop accepts values in one of the following formats:

  1. Array of strings:
import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect data={['React', 'Angular', 'Svelte', 'Vue']} />
  );
}
  1. Array of objects with label, value and disabled keys:
import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect
      data={[
        { label: 'React', value: 'react' },
        { label: 'Angular', value: 'angular' },
        { label: 'Svelte', value: 'svelte', disabled: true },
        { label: 'Vue', value: 'vue' },
      ]}
    />
  );
}
  1. Array of grouped options (string format):
import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect
      data={[
        {
          group: 'Frontend libraries',
          items: ['React', 'Angular', 'Svelte', 'Vue'],
        },
        {
          group: 'Backend libraries',
          items: ['Express', 'Koa', 'Django'],
        },
      ]}
    />
  );
}
  1. Array of grouped options (object format):
import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect
      data={[
        {
          group: 'Frontend libraries',
          items: [
            { label: 'React', value: 'react' },
            { label: 'Angular', value: 'angular' },
            { label: 'Vue', value: 'vue', disabled: true },
          ],
        },
        {
          group: 'Backend libraries',
          items: [
            { label: 'Express', value: 'express' },
            { label: 'Koa', value: 'koa' },
            { label: 'Django', value: 'django' },
          ],
        },
      ]}
    />
  );
}

Example of the data prop with an array of grouped options:

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect
      data={[
        {
          group: 'Frontend libraries',
          items: [
            { label: 'React', value: 'react' },
            { label: 'Angular', value: 'angular' },
            { label: 'Vue', value: 'vue', disabled: true },
          ],
        },
        {
          group: 'Backend libraries',
          items: [
            { label: 'Express', value: 'express' },
            { label: 'Koa', value: 'koa' },
            { label: 'Django', value: 'django' },
          ],
        },
      ]}
    />
  );
}

children options

To add options with the children prop, use option elements to add options and optgroup elements to group them:

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect label="With children options">
      <optgroup label="Frontend libraries">
        <option value="react">React</option>
        <option value="angular">Angular</option>
        <option value="vue" disabled>
          Vue
        </option>
      </optgroup>

      <optgroup label="Backend libraries">
        <option value="express">Express</option>
        <option value="koa">Koa</option>
        <option value="django">Django</option>
      </optgroup>
    </NativeSelect>
  );
}

With dividers

Use hr tags to add dividers between options:

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <NativeSelect label="With dividers">
      <option>Select library</option>

      <hr />

      <optgroup label="Frontend libraries">
        <option value="react">React</option>
        <option value="angular">Angular</option>
        <option value="vue">Vue</option>
      </optgroup>

      <hr />

      <optgroup label="Backend libraries">
        <option value="express">Express</option>
        <option value="koa">Koa</option>
        <option value="django">Django</option>
      </optgroup>
    </NativeSelect>
  );
}

Left and right sections

NativeSelect supports leftSection and rightSection props. These sections are rendered with absolute positioning inside the input wrapper. You can use them to display icons, input controls, or any other elements.

You can use the following props to control sections styles and content:

  • rightSection / leftSection – React node to render on the corresponding side of input
  • rightSectionWidth/leftSectionWidth – controls the width of the right section and padding on the corresponding side of the input. By default, it is controlled by the component size prop.
  • rightSectionPointerEvents/leftSectionPointerEvents – controls the pointer-events property of the section. If you want to render a non-interactive element, set it to none to pass clicks through to the input.
import { NativeSelect } from '@mantine/core';
import { CaretDownIcon, HashIcon } from '@phosphor-icons/react';

function Demo() {
  return (
    <>
      <NativeSelect
        leftSection={<HashIcon size={16} />}
        leftSectionPointerEvents="none"
        label="Left section"
        data={['React', 'Angular']}
      />

      <NativeSelect
        rightSection={<CaretDownIcon size={16} />}
        label="Right section"
        data={['React', 'Angular']}
        mt="md"
      />
    </>
  );
}

Disabled state

import { NativeSelect } from '@mantine/core';

function Demo() {
  return <NativeSelect disabled data={['React', 'Angular']} label="Disabled NativeSelect" />;
}

Error state

Error message

import { NativeSelect } from '@mantine/core';

function Demo() {
  return (
    <>
      <NativeSelect error label="Boolean error" data={['React', 'Angular']} />
      <NativeSelect
        error="Error message"
        label="React node error"
        data={['React', 'Angular']}
        mt="md"
      />
    </>
  );
}

Styles API

NativeSelect supports the Styles API; you can add styles to any inner element of the component with the classNames prop. Follow the Styles API documentation to learn more.

NativeSelect description

NativeSelect error

Component Styles API

Hover over selectors to highlight corresponding elements

/*
 * Hover over selectors to apply outline styles
 *
 */

Accessibility

If NativeSelect is used without the label prop, it will not be announced properly by screen readers:

import { NativeSelect } from '@mantine/core';

// Inaccessible input – screen reader will not announce it properly
function Demo() {
  return <NativeSelect />;
}

Set aria-label to make the input accessible. In this case the label will not be visible, but screen readers will announce it:

import { NativeSelect } from '@mantine/core';

// Accessible input – it has aria-label
function Demo() {
  return <NativeSelect aria-label="My input" />;
}

If the label prop is set, the input will be accessible and it is not required to set aria-label:

import { NativeSelect } from '@mantine/core';

// Accessible input – it has associated label element
function Demo() {
  return <NativeSelect label="My input" />;
}