Combobox
<mo-combobox> | MOCombobox
A combo box consists of a list and a selection field. The list presents the options that a user can select, and the selection field displays the current selection.
<mo-combobox></mo-combobox>
Simple combobox
Use the options
attribute to give the mo-combobox
an array of options. The tree
structure will be generated based on this array.
<mo-combobox label="Country" placeholder="Type to search" class="combobox-local" clearable> </mo-combobox> <script> const combobox = document.querySelector('.combobox-local'); const fetchData = async () => { try { const response = await fetch('/api/countries'); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); return data; } catch (error) { console.error('There has been a problem with your fetch operation:', error); } }; const setOptions = async () => { const data = await fetchData(); combobox.options = data; } setOptions(); </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const countries = [{...}]; const App = () => ( <> <MOCombobox label="Country" placeholder="Type to search" clearable closeOnSelection options={countries} ></MOCombobox> </> );
Enabling the close-on-selection
attribute will close the dropdown when an item is selected,
if the selection-mode
is set to single
or leaf
. This can lead to a
better user experience.
Hierarchical structure
Supplying the mo-combobox
with a list of tree items using the treeItems
attribute
allows for hierarchical a tree structure inside the dropdown.
<mo-combobox label="Celestial objects" placeholder="Select variable" id="tree-box" hierarchical-content clearable ></mo-combobox> <script> const treeBox = document.querySelector('#tree-box'); const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable treeItems={treeItems}></MOCombobox> </> );
Enabling virtualization is recommended when dealing with over a couple hundred nodes.
Multiple selection
Setting the attribute selection-mode
to multiple
will add checkboxes to the
mo-tree
that will allow multiple nodes to be selected simultaneously.
<mo-combobox label="Celestial objects" placeholder="Select variable(s)" id="tree-box-multiple" clearable help-text="Multiple nodes can be selected." selection-mode="multiple" ></mo-combobox> <script> const treeBox = document.querySelector('#tree-box-multiple'); const treeItems = [ { id: '1', name: 'Galaxies', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1', favorite: true }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3', favorite: true }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1', favorite: true }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5', favorite: true } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2', favorite: true } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3', favorite: true }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2', favorite: true }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable selection-mode="single" treeItems={treeItems} ></MOCombobox> </> );
When multiple selection is enabled, manual search is not available.
Show path first
Enabling the attribute show-path-first
offers an alternate way of displaying the paths to
variables shown in manual search queries, in the favorites, and in the input value field.
<mo-combobox label="Celestial objects" placeholder="Select variable" id="tree-path" favorites show-path-first clearable separator=">" ></mo-combobox> <script> const treeBox = document.querySelector('#tree-path'); const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1', favorite: true }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3', favorite: true }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1', favorite: true }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5', favorite: true } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2', favorite: true } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3', favorite: true }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2', favorite: true }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1', favorite: true }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3', favorite: true }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1', favorite: true }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5', favorite: true } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2', favorite: true } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3', favorite: true }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2', favorite: true }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable treeItems={treeItems} separator=">" ></MOCombobox> </> );
The separator
attribute can be used to change the separator between path nodes.
Controlled and initial selection
You can set the value
attribute to a node id for single selection, and to a space-separated
string of id’s for the multiple selection (as attribute, HTML), or an array of strings (as property,
JavaScript/React).
Note that for multiple selection, only leaf nodes are included in the value
.
selected nodes:
<div> <mo-combobox style="flex: 1 1 auto;" label="Celestial objects" placeholder="Select variable" selection-mode="single" value="1-1-2" id="tree-controlled" help-text="Choose one option" clearable ></mo-combobox> <mo-input help-text="Input node id to be selected here." id="node-id-input" placeholder="Example: 2-3-1-2" value="1-1-2" label="value" ></mo-input> </div> <mo-divider></mo-divider> <div> <mo-combobox style="flex: 1 1 auto;" label="Celestial objects" placeholder="Select variable" id="tree-controlled-multiple" help-text="Multiple options can be selected" value="2-1-1 1-1-2" selection-mode="multiple" clearable ></mo-combobox> <mo-input id="node-id-input-multiple" value="2-1-1 1-1-2" help-text="Input node id to be selected here." placeholder="Example: 2-1-1 1-1-2" label="value" ></mo-input> </div> <pre id="pre">selected nodes:</pre> <script> const treeBox = document.querySelector('#tree-controlled'); const treeBoxMulti = document.querySelector('#tree-controlled-multiple'); const input = document.querySelector('#node-id-input'); const inputMulti = document.querySelector('#node-id-input-multiple'); const pre = document.querySelector('#pre'); const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2', selected: true }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; treeBoxMulti.treeItems = treeItems; treeBoxMulti.addEventListener('mo-selection-change', e => { pre.textContent = 'selected nodes: ' + treeBoxMulti.value; }); input.addEventListener('mo-input', () => { treeBox.value = input.value; }); inputMulti.addEventListener('mo-input', () => { treeBoxMulti.value = inputMulti.value; }); </script>
import { MOCombobox, MODivider, MOInput, MOButton } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const inputRef = useRef(null); const cbRef = useRef(null); const setNode = () => { cbRef.current.selectNode(cbRef.current.getNodeById(inputRef.value)); }; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable ref={cbRef} treeItems={treeItems} ></MOCombobox> <MODivider></MODivider> <MOInput ref={inputRef} placeholder="Example: 2-3-1-2" label="Node id"></MOInput> <br /> <MOButton onClick={setNode}>Select node</MOButton> </> );
Before 4.0, the initial selection could be achieved by setting selected: true
on the nodes
themselves in the treeItems
object. This is deprecated in >4.0 and the behavior should be
implemented as described above.
Form submission
If the required attribute is set to true
, the combobox will stop form submission if no value
has been selected. Check the example below on how to extract the current value on form submission.
<form class="form" id="req-form"> <mo-combobox name="combobox-simple" label="Countries" placeholder="Select country" id="simple-form" required close-on-selection clearable ></mo-combobox> <br /> <mo-combobox name="combobox-tree" label="Celestial objects" placeholder="Select object" id="tree-form" required clearable ></mo-combobox> <br /> <mo-button type="submit" id="submit-btn">Submit</mo-button> <mo-divider></mo-divider> <pre id="data">submitted data will be here...</pre> </form> <script> const treeBox = document.querySelector('#tree-form'); const simpleBox = document.querySelector('#simple-form'); const btn = document.querySelector('#submit-btn'); const countries = [ { text: 'Finland', value: 'finland' }, { text: 'Sweden', value: 'sweden' }, { text: 'Germany', value: 'germany' }, { text: 'Denmark', value: 'denmark' }, { text: 'Norway', value: 'norway' } ]; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; simpleBox.options = countries; const form = document.querySelector('#req-form'); const output = document.querySelector('#data'); form.addEventListener('submit', e => { e.preventDefault(); const formData = new FormData(form); console.log(formData); var object = {}; formData.forEach((value, key) => (object[key] = value)); var json = JSON.stringify(object, null, 2); output.innerHTML = json; }); </script>
import { MOCombobox, MODivider, MOButton } from '@metsooutotec/modes-web-components/dist/react'; const countries = [ { text: 'Finland', value: 'finland' }, { text: 'Sweden', value: 'sweden' }, { text: 'Germany', value: 'germany' }, { text: 'Denmark', value: 'denmark' }, { text: 'Norway', value: 'norway' } ]; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; // Form submission logic here... const App = () => ( <> <form class="form" id="req-form"> <MOCombobox name="combobox-simple" label="Countries" placeholder="Select country" id="simple-form" required closeOnSelection clearable ></MOCombobox> <br /> <MOCombobox name="combobox-tree" label="Celestial objects" placeholder="Select object" id="tree-form" required clearable ></MOCombobox> <br /> <MOButton type="submit" id="submit-btn"> Submit </MOButton> <MODivider></MODivider> <pre id="data">submitted data will be here...</pre> </form> </> );
The simple combobox returns the name
value of the chosen option on form submission, and the
hierarchical variant will return the id
of the selected node. If the selected node does not
have an id
defined, it will fall back to the node’s name
value.
With favorites
Enabling the attribute favorites
will allow users to select favorites in the tree, which will
be shown as a top category. Each node in the data tree can have an optional favorite
property,
if set to true that node will be a favorite. This way favorites can easily be saved in the backend on a
per-user basis.
<mo-combobox label="Celestial objects" placeholder="Select variable" id="tree-box-favorites" prevent-automatic-expanding clearable favorites ></mo-combobox> <script> const treeBox = document.querySelector('#tree-box-favorites'); const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1', favorite: true }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3', favorite: true }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1', favorite: true }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5', favorite: true } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2', favorite: true } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3', favorite: true }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2', favorite: true }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1', favorite: true }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3', favorite: true }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1', favorite: true }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5', favorite: true } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2', favorite: true } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3', favorite: true }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2', favorite: true }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable favorites treeItems={treeItems} ></MOCombobox> </> );
Each node must have a unique identifier id
to ensure favorites are toggled correctly.
Selectable categories
The attribute selection-mode
dictates how the selection is applied when clicking on the tree
items inside the tree. By default it is set to leaf
, where only leaf nodes are selectable.
Setting it to single
allows categories to be selectable as well.
<mo-combobox label="Celestial objects" placeholder="Select variable" id="tree-box-selection" clearable required help-text="Categories can be selected as well." selection-mode="single" ></mo-combobox> <script> const treeBox = document.querySelector('#tree-box-selection'); const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; treeBox.treeItems = treeItems; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; const treeItems = [ { name: 'Galaxies', id: '1', children: [ { name: 'Elliptical', id: '1-1', children: [ { name: 'IC 1101', id: '1-1-1' }, { name: 'Hercules A', id: '1-1-2' }, { name: 'A2261-BCG', id: '1-1-3' }, { name: 'ESO 306-17', id: '1-1-4' }, { name: 'ESO 444-46', id: '1-1-5' } ] }, { name: 'Spiral', id: '1-2', children: [ { name: "Rubin's Galaxy", id: '1-2-1' }, { name: 'Comet Galaxy', id: '1-2-2' }, { name: 'Condor Galaxy', id: '1-2-3' }, { name: 'Tadpole Galaxy', id: '1-2-4' }, { name: 'Andromeda Galaxy', id: '1-2-5' } ] } ] }, { name: 'Planets', id: '2', children: [ { name: 'Sub-Earth', id: '2-1', children: [ { name: 'Mars', id: '2-1-1' }, { name: 'Mercury', id: '2-1-2' } ] }, { name: 'Giant', id: '2-2', children: [ { name: 'Jupiter', id: '2-2-1' }, { name: 'Saturn', id: '2-2-2' }, { name: 'Uranus', id: '2-2-3' }, { name: 'Neptune', id: '2-2-4' } ] }, { name: 'Exoplanet', id: '2-3', children: [ { name: 'Potentially habitable', id: '2-3-1', children: [ { name: 'Alpha Centauri', id: '2-3-1-1' }, { name: 'Ross 128', id: '2-3-1-2' }, { name: 'Wolf 1061', id: '2-3-1-3' } ] }, { name: 'Epsilon Eridani', id: '2-3-2' }, { name: 'YZ Ceti', id: '2-3-4' } ] } ] } ]; const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable required selection-mode="single" treeItems={treeItems} ></MOCombobox> </> );
Virtualization (stress test)
The mo-combobox
can handle massive trees by only loading items in to the DOM once they are
visible and needed. This behavior can be enabled by using the virtualization
attribute.
<mo-combobox label="Celestial objects" placeholder="Select variable" id="tree-box-tons" virtualization clearable ></mo-combobox> This example has 3<sup>7</sup> = 2 187 nodes. <script> const treeBox = document.querySelector('#tree-box-tons'); function generateItems(depth) { function getRandomInt(max) { return Math.ceil(Math.random() * max); } function generateId() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) ); } const items = []; if (depth < 7) { for (let i = 0; i < 3; i++) { items.push({ name: `item ${getRandomInt(1000)}`, id: generateId(), children: generateItems(depth + 1) }); } } return items; } const trees = generateItems(0); treeBox.treeItems = trees; </script>
import { MOCombobox } from '@metsooutotec/modes-web-components/dist/react'; function generateItems(depth) { function getRandomInt(max) { return Math.ceil(Math.random() * max); } function generateId() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) ); } const items = []; if (depth < 7) { for (let i = 0; i < 3; i++) { items.push({ name: `item ${getRandomInt(1000)}`, id: generateId(), children: generateItems(depth + 1) }); } } return items; } const trees = generateItems(0); const App = () => ( <> <MOCombobox label="Celestial objects" placeholder="Select variable" clearable virtualization treeItems={trees}></MOCombobox> This example has 3<sup>10</sup> = 59 094 nodes. </> );
Due to the virtualization only rendering the items when necessary, virtualization
and
favorites
are mutually exclusive. selectionMode = multiple
also
functions significantly better with virtualization
disabled.
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component using a bundler:
import '@metsooutotec/modes-web-components/dist/components/combobox/combobox.js';
To import this component as a React component:
import MOCombobox from '@metsooutotec/modes-web-components/dist/react/combobox/';
To import this component using a script tag:
<script type="module" src="https://modes-web.metso.com/dist/components/cdn/components/combobox/combobox.js"></script>
Properties
Name | Description | Reflects | Type | Default |
---|---|---|---|---|
input
|
The input element. |
MOInput
|
- | |
hiddenInput
|
The hidden input element. |
HTMLInputElement
|
- | |
dropdown
|
The dropdown element. |
MODropdown
|
- | |
menu
|
The menu element. |
MOMenu
|
- | |
tree
|
The tree element. |
MOTree
|
- | |
treeItemNodes
|
List of all tree item nodes. |
MOTreeItem[]
|
- | |
suggestions
|
Options filtered based on search query. |
{ text: string; value: string }[] | undefined
|
undefined
|
|
filteredTreeItems
|
Tree items that have been filtered based on search query. |
TreeNode[] | undefined
|
undefined
|
|
favoriteNodes
|
List of all tree items that have been favorited and will be rendered in their own group. |
TreeNode[]
|
[]
|
|
selectedNode
|
The currently selected node (in tree structure). |
TreeNode | undefined
|
undefined
|
|
selectedNodes
|
The currently selected nodes (in tree structure). Use with selectionMode = “multiple” |
TreeNode[]
|
[]
|
|
options
|
All the different options for the simple combobox. |
{ text: string; value: string }[]
|
[]
|
|
size
|
The combobox’s size. |
|
'small' | 'medium' | 'large'
|
'medium'
|
favorites
|
Allows selection of favoriteNodes in the tree view. Should only be used when
treeItems is defined.
|
|
boolean
|
false
|
selectionMode
selection-mode
|
The selection mode of the items in the tree. Defaults to leaf (only leafs are
selectable, i.e., not groups).
|
|
'single' | 'leaf' | 'multiple'
|
'leaf'
|
label
|
The combobox’s label. |
string
|
''
|
|
name
|
The combobox’s name attribute. |
string
|
- | |
searchFn
|
The search function that is used when filtering the combobox through manual input. |
(term: string, node: TreeNode) => boolean
|
- | |
visibleValue
|
The combobox’s visible value attribute. |
string
|
''
|
|
value
|
The current value of the combobox, submitted as a name/value pair with form data. When
multiple is enabled, the value attribute will be a space-delimited list of values based
on the options selected, and the value property will be an array.
For this reason, values must not contain spaces.
|
string | string[]
|
''
|
|
maxTagsVisible
max-tags-visible
|
The maximum number of tags to show when selectionMode === multiple . After the maximum,
”+n” will be shown to indicate the number of additional items that are selected. Set to -1 to remove
the limit.
|
number
|
3
|
|
maxNodesShown
max-nodes-shown
|
The maximum number of tags to show when selectionMode === multiple . After the maximum,
”+n” will be shown to indicate the number of additional items that are selected. Set to -1 to remove
the limit.
|
number
|
20
|
|
helpText
help-text
|
The combobox’s help text. |
string
|
''
|
|
error
|
Renders the field in an error state |
|
boolean
|
false
|
success
|
Renders the field in a success state |
|
boolean
|
false
|
errorText
error-text
|
Error text to show in place of help text when input is invalid. |
string
|
''
|
|
successText
success-text
|
Success text to show in place of help text when input is valid. |
string
|
''
|
|
separator
|
The combobox’s help text. |
string
|
'/'
|
|
clearable
|
Adds a clear button when the input is populated. |
boolean
|
false
|
|
hoist
|
Enable this option to prevent the panel from being clipped when the component is placed inside a
container with overflow: auto|scroll .
|
boolean
|
false
|
|
showPathFirst
show-path-first
|
Enable this option to show the path first, before the variable name, in manual search and favorite listings. |
boolean
|
false
|
|
closeOnSelection
close-on-selection
|
Indicates whether the combobox dropdown should close automatically when an item is selected. |
|
boolean
|
false
|
placeholder
|
The input’s placeholder text. |
string
|
- | |
autofocus
|
The input’s autofocus attribute. |
boolean
|
- | |
disabled
|
Disables the combobox component. |
|
boolean
|
false
|
required
|
The combobox’s required attribute. |
|
boolean
|
false
|
invalid
|
This will be true when the control is in an invalid state. Validity is determined by the
required prop.
|
|
boolean
|
false
|
minChars
min-chars
|
The minimum chars that will triggered the combobox suggestions. |
number
|
0
|
|
emptyMessage
empty-message
|
Message displayed when no result found. |
string
|
'No matches found.'
|
|
loadingMessage
empty-message
|
Message displayed when no result found. |
string
|
'Loading more items…'
|
|
virtualization
|
When enabled, the tree items are added to the DOM when their parent is opened. |
|
boolean
|
false
|
preventAutomaticExpanding
prevent-automatic-expanding
|
Prevents the tree nodes closing and expanding automatically based on selection. |
|
boolean
|
false
|
getChip
|
A function that customizes the chips to be rendered when multiple=true. The first argument is the option, the second is the current chip’s index. The function should return either a Lit TemplateResult or a string containing trusted HTML of the symbol to render at the specified value. |
(node: TreeNode, index: number) => TemplateResult | string | HTMLElement
|
- | |
validity
|
Gets the validity state object | - | - | |
validationMessage
|
Gets the validation message | - | - | |
chips
|
Returns an array of chips representing the selected nodes. | - | - | |
updateComplete |
A read-only promise that resolves when the component has finished updating. |
Learn more about attributes and properties.
Events
Name | React Event | Description | Event Detail |
---|---|---|---|
mo-selection-change |
onMoSelectionChange |
Emitted when an item gets selected or deselected |
{ selection: this.selectedItems }
|
mo-select |
onMoSelect |
Emitted when the input’s value changes. | - |
mo-clear |
onMoClear |
Emitted when the clear button is activated. | - |
mo-input |
onMoInput |
Emitted when the input receives input. | - |
mo-focus |
onMoFocus |
Emitted when the input gains focus. | - |
mo-blur |
onMoBlur |
Emitted when the input loses focus. | - |
mo-show |
onMoShow |
Emitted when the dropdown opens. | - |
mo-after-show |
onMoAfterShow |
Emitted after the dropdown opens and all animations are complete. | - |
mo-hide |
onMoHide |
Emitted when the dropdown closes. | - |
mo-after-hide |
onMoAfterHide |
Emitted after the dropdown closes and all animations are complete.* | - |
Learn more about events.
Methods
Name | Description | Arguments |
---|---|---|
checkValidity() |
Checks for validity but does not show a validation message. Returns true when valid and
false when invalid.
|
- |
getForm() |
Gets the associated form, if one exists. | - |
reportValidity() |
Checks for validity and shows the browser’s validation message if the control is invalid. | - |
setCustomValidity() |
Sets a custom validation message. If message is not empty, the field will be considered
invalid.
|
message: string
|
toggleDropdown() |
Toggles the visibility of the dropdown. | - |
reset() |
Resets the combobox to its initial state. | - |
findNodeIndex() |
Finds the index path of a given node within a tree. |
currentNode: TreeNode, nodeToFind: TreeNode
|
getNodeById() |
Retrieves a node from the tree by its ID. |
id: string
|
handleTreeChange() |
Handles the change event of the tree component. |
event: TreeChangeEvent
|
Learn more about methods.
Custom Properties
Name | Description | Default |
---|---|---|
--max-items-to-show |
Dictates max-height of the dropdown together with --item-height . |
Learn more about customizing CSS custom properties.
Parts
Name | Description |
---|---|
base |
The component’s base wrapper. |
label |
The input label. |
dropdown |
The dropdown control. |
input |
The input control. |
tags |
The tags to indicate multiple selection. |
help-text |
The input help text. |
Learn more about customizing CSS parts.
Dependencies
This component automatically imports the following dependencies.