Package Exports
- @material/select
- @material/select/constants
- @material/select/dist/mdc.select
- @material/select/dist/mdc.select.css
- @material/select/dist/mdc.select.js
- @material/select/foundation
- @material/select/foundation.js
- @material/select/index
- @material/select/index.js
- @material/select/mdc-select.scss
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@material/select) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Select Menus
MDC Select provides Material Design single-option select menus. It functions analogously to the
browser's native <select>
element, and includes a gracefully degraded version that can be used
in conjunction with the browser's native element. Both are fully accessible, and fully RTL-aware.
Design & API Documentation
Installation
npm install --save @material/select
Usage
Using the full-fidelity JS component
<div class="mdc-select" role="listbox">
<div class="mdc-select__surface" tabindex="0">
<div class="mdc-select__label">Pick a Food Group</div>
<div class="mdc-select__selected-text"></div>
<div class="mdc-select__bottom-line"></div>
</div>
<div class="mdc-menu mdc-select__menu">
<ul class="mdc-list mdc-menu__items">
<li class="mdc-list-item" role="option" tabindex="0">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Vegetables
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fruit
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
Then with JS
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
select.listen('MDCSelect:change', () => {
alert(`Selected "${select.selectedOptions[0].textContent}" at index ${select.selectedIndex} ` +
`with value "${select.value}"`);
});
See Importing the JS component for more information on how to import JavaScript.
Note that you can include mdc-select via a UMD bundle, which will be available post-alpha.
Note that the full-fidelity version of MDC Select requires you to manually include the styles for mdc-menu and mdc-list. If you are using the material-components-web package, this is taken care of for you and you simply need to import the main stylesheet. Otherwise, you must ensure that you manually include the style dependencies for both the mdc-list and mdc-menu for this component to function properly.
Select with pre-selected option
When dealing with the select component that has pre-selected values, you'll want to ensure that you
render mdc-select__label
with the mdc-select__label--float-above
modifier class and the selected
option with aria-selected
. This will ensure that the label moves out of the way of the select's value
and prevents a Flash Of Un-styled Content (FOUC).
<div class="mdc-select" role="listbox">
<div class="mdc-select__surface" tabindex="0">
<div class="mdc-select__label mdc-select__label--float-above">Pick a Food Group</div>
<div class="mdc-select__selected-text"></div>
<div class="mdc-select__bottom-line"></div>
</div>
<div class="mdc-menu mdc-select__menu">
<ul class="mdc-list mdc-menu__items">
<li class="mdc-list-item" role="option" tabindex="0">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Vegetables
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fruit
</li>
<li class="mdc-list-item" role="option" aria-selected tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
Disabled select
<div class="mdc-select" role="listbox" aria-disabled="true">
<div class="mdc-select__surface" tabindex="-1">
<div class="mdc-select__label">Pick a Food Group</div>
<div class="mdc-select__selected-text"></div>
<div class="mdc-select__bottom-line"></div>
</div>
<div class="mdc-menu mdc-select__menu">
<ul class="mdc-list mdc-menu__items">
<li class="mdc-list-item" role="option" tabindex="0">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Vegetables
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fruit
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
Disabled options
When used in components such as MDC Select, mdc-list-item
s can be disabled.
To disable a list item, set aria-disabled
to "true"
, and set tabindex
to "-1"
.
<div class="mdc-select" role="listbox">
<div class="mdc-select__surface" tabindex="0">
<div class="mdc-select__label">Pick a Food Group</div>
<div class="mdc-select__selected-text"></div>
<div class="mdc-select__bottom-line"></div>
</div>
<div class="mdc-menu mdc-select__menu">
<ul class="mdc-list mdc-menu__items">
<li class="mdc-list-item" role="option" tabindex="0">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" role="option" aria-disabled="true" tabindex="-1">
Vegetables
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fruit
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Milk, Yogurt, and Cheese
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Meat, Poultry, Fish, Dry Beans, Eggs, and Nuts
</li>
<li class="mdc-list-item" role="option" tabindex="0">
Fats, Oils, and Sweets
</li>
</ul>
</div>
</div>
CSS Classes
Class | Description |
---|---|
mdc-select |
Mandatory. |
mdc-select--box |
Styles the select as a box select. |
mdc-list-group |
A group of options. |
mdc-list-item |
A list item. |
mdc-list-divider |
A divider. |
It is advised that dividers also set role="presentation"
to disable selection and not cloud accessibility.
Sass Mixins
To customize the colors of any part of the select, use the following mixins. We recommend you use
these mixins within CSS selectors like .foo-select
to apply styling.
Mixin | Description |
---|---|
mdc-select-ink-color($color) |
Customizes the color of the selected item displayed in the select. |
mdc-select-container-fill-color($color) |
Customizes the background color of the select. |
mdc-select-label-color($color) |
Customizes the label color of the select in the unfocused state. |
mdc-select-focused-label-color($color, $opacity: 0.87) |
Customizes the label color of the select when focused. Changing opacity for the label when floating is optional. |
mdc-select-bottom-line-color($color) |
Customizes the color of the default bottom line of the select. |
mdc-select-focused-bottom-line-color($color) |
Customizes the color of the bottom line of the select when focused. |
To customize the color of the list items, refer to the List documentation.
MDC Select Component API
The MDC Select component API is modeled after a subset of the HTMLSelectElement
functionality, and
is outlined below.
Properties
Property Name | Type | Description |
---|---|---|
value |
string |
(read-only) The id of the currently selected option. If no id is present on the selected option, its textContent is used. Returns an empty string when no option is selected. |
options |
HTMLElement[] |
(read-only) An array of menu items comprising the select's options. |
selectedIndex |
number |
The index of the currently selected option. Set to -1 if no option is currently selected. Changing this property will update the select element. |
selectedOptions |
HTMLElement[] |
(read-only) A NodeList of either the currently selected option, or no elements if nothing is selected. |
disabled |
boolean |
Whether or not the component is disabled. Settings this sets the disabled state on the component. |
Methods
Method Signature | Description |
---|---|
item(index: number) => HTMLElement? |
Analogous to HTMLSelectElement.prototype.item . Returns the option at the specified index, or null if the index is out of bounds. } |
nameditem(key: string) => HTMLElement? |
Analogous to HTMLSelectElement.prototype.nameditem . Returns the options either whose id equals the given key , or whose name attribute equals the given key . Returns null if no item with an id or name attribute of the specified key is found. |
Events
The MDC Select JS component emits an MDCSelect:change
event when the selected option changes as
the result of a user action.
Using the foundation class
MDC Select ships with a foundation class that framework authors can use to integrate MDC Select into their custom components. Note that due to the nature of MDC Select, the adapter is quite complex. We try to provide as much guidance as possible, but we encourage developers to reach out to us via GH Issues if they run into problems.
Notes for component implementors
The MDCSelectFoundation
expects that the select component conforms to the following two requirements:
The component owns an element that's used as its select menu, e.g. its menu element.
The component controls an instance of
MDCMenu
, which is attached to its menu element.
We achieve this by accepting a menuFactory
optional constructor parameter, which is a function
which is passed our menu element, and is expected to return an MDCMenu
component instance.
If you are attempting to implement mdc-select for your framework, and you find that this approach
does not work for you, and there is no suitable way to satisfy the above two requirements, please
open an issue.
MDCSelectFoundation
also has the ability to resize itself whenever its options change, via the
resize()
method. We recommend calling this method on initialization, or when the menu items are
modified. For example, if building a react component, it may be appropriate to call resize()
within componentDidUpdate
.
Adapter API
Method Signature | Description |
---|---|
addClass(className: string) => void |
Adds a class to the root element. |
removeClass(className: string) => void |
Removes a class from the root element. |
floatLabel(value: boolean) => void |
Float or defloats label as necessary |
addClassToBottomLine(className: string) => void |
Adds a class to the bottom line |
removeClassFromBottomLine(className: string) => void |
Removes a class from the bottom line |
setBottomLineAttr(attr: string, value: string) => void |
Adds an attribute to the bottom line |
addBodyClass(className: string) => void |
Adds a class to the body. |
removeBodyClass(className: string) => void |
Removes a class from the body. |
setAttr(attr: string, value: string) => void |
Sets attribute attr to value value on the root element. |
rmAttr(attr: string) => void |
Removes attribute attr from the root element. |
computeBoundingRect() => {left: number, top: number} |
Returns an object with a shape similar to a ClientRect object, with a left and top property specifying the element's position on the page relative to the viewport. The easiest way to achieve this is by calling getBoundingClientRect() on the surface element. |
registerInteractionHandler(type: string, handler: EventListener) => void |
Adds an event listener handler for event type type on the surface element. |
deregisterInteractionHandler(type: string, handler: EventListener) => void |
Removes an event listener handler for event type type on the surface element. |
focus() => void |
Focuses the surface element |
makeTabbable() => void |
Allows the surface element to be tab-focused via keyboard. We achieve this by setting the surface element's tabIndex property to 0 . |
makeUntabbable() => void |
Disallows the surface element from being tab-focused via keyboard. We achieve this by setting the surface element's tabIndex property to -1 . |
getComputedStyleValue(propertyName: string) => string |
Get the surface element's computed style value of the given dasherized css property propertyName . We achieve this via getComputedStyle(...).getPropertyValue(propertyName). |
setStyle(propertyName: string, value: string) => void |
Sets a dasherized css property propertyName to the value value on the surface element. We achieve this via root.style.setProperty(propertyName, value) . |
create2dRenderingContext() => {font: string, measureText: (string) => {width: number}} |
Returns an object which has the shape of a CanvasRenderingContext2d instance. Namely, it has a string property font which is writable, and a method measureText which given a string of text returns an object containing a width property specifying how wide that text should be rendered in the font specified by the font property. An easy way to achieve this is simply document.createElement('canvas').getContext('2d'); . |
setMenuElStyle(propertyName: string) => void |
Sets a dasherized css property propertyName to the value value on the menu element. |
setMenuElAttr(attr: string, value: string) => void |
Sets attribute attr to value value on the menu element. |
rmMenuElAttr(attr: string) => void |
Removes attribute attr from the menu element. |
getMenuElOffsetHeight() => number |
Returns the offsetHeight of the menu element. |
openMenu(focusIndex: string) => void |
Opens the select's menu with focus on the option at the given focusIndex . The focusIndex is guaranteed to be in bounds. |
isMenuOpen() => boolean |
Returns true if the menu is open, false otherwise. |
setSelectedTextContent(selectedTextContent: string) => void |
Sets the text content of the .mdc-select__selected-text element to selectedTextContent . |
getNumberOfOptions() => number |
Returns the number of options contained in the select's menu. |
getTextForOptionAtIndex(index: number) => string |
Returns the text content for the option at the specified index within the select's menu. |
getValueForOptionAtIndex(index: number) => string |
Returns the value for the option at the specified index within the select's menu. We adhere to the conventions of HTMLSelectElement - as described above - returning the value of the selected option's id in place of a value attribute and falling back to its textContent . Framework implementations may want to customize this method to suit their needs. |
setAttrForOptionAtIndex(index: number, attr: string, value: string) => void |
Sets an attribute attr to value value for the option at the specified index within the select's menu. |
rmAttrForOptionAtIndex(index: number, attr: string) => void |
Removes an attribute attr for the option at the specified index within the select's menu. |
getOffsetTopForOptionAtIndex(index: number) => number |
Returns the offsetTop of the option element at the specified index. The index is guaranteed to be in bounds. |
registerMenuInteractionHandler(type: string, handler: EventListener) => void |
Registers an event listener on the menu component's root element. Note that we will always listen for MDCMenu:selected for change events, and MDCMenu:cancel to know that we need to close the menu. If you are using a different events system, you could check the event type for either one of these strings and take the necessary steps to wire it up. |
deregisterMenuInteractionHandler(type: string, handler: EventListener) => void |
Opposite of registerMenuInteractionHandler . |
notifyChange() => void |
Broadcast a change event, similar to the change event emitted by an HTMLSelectElement . While we use custom events in our implementation for this, you can use any mechanism desired for notifications, such as callbacks, reactive streams, etc. Note that you can also pass data within your event if you'd like via foundation.getValue() and foundation.getSelectedIndex() . |
getWindowInnerHeight() => number |
Returns the innerHeight property of the window element. |
The full foundation API
MDCSelectFoundation.getValue() => string
Returns the value of the currently selected option, or an empty string if no option is selected.
MDCSelectFoundation.getSelectedIndex() => number
Returns the index of the currently selected option. Returns -1 if no option is currently selected.
MDCSelectFoundation.setSelectedIndex(selectedIndex: number) => void
Sets the selected index of the component.
MDCSelectFoundation.isDisabled() => boolean
Returns whether or not the select is disabled.
MDCSelectFoundation.setDisabled(disabled: boolean) => void
Enables/disables the select.
Theming
The select's bottom border is set to the current theme's primary color when focused.