Lookup
Menu component with a text input and a menu of options.
Options will depend on the current value of the input. Typical use will involve listening for new-input
events, fetching or otherwise computing options, then passing those options back to the Lookup for display.
TextInput props apply
This component contains a TextInput component. You can bind TextInput props to this component and they will be passed to the TextInput within.
Attributes passed to input
This component will pass any HTML attributes applied to it, except for CSS class, to the <input>
element within the component.
Demos
Default
The Lookup component will emit new-input
events on input, which the parent component can react to by computing or fetching options, then providing those options to the Lookup component for display.
Note that in this example, options are Wikidata items with a human-readable label and a Wikidata entity ID value.
<template>
<div>
<p>The current value is: {{ selection }}</p>
<cdx-lookup
v-model="selection"
:options="menuOptions"
@new-input="onInput"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CdxLookup } from 'vue-components/src/lib';
import { MenuOption } from 'vue-components/src/types';
import vegetableItems from './data';
export default defineComponent( {
name: 'LookupDefault',
components: { CdxLookup },
setup() {
const selection = ref( '' );
const menuOptions = ref<MenuOption[]>( [] );
function onInput( value: string ) {
if ( value ) {
menuOptions.value = vegetableItems.filter( ( item ) =>
item.label.includes( value )
);
}
}
return {
selection,
menuOptions,
onInput
};
}
} );
</script>
The menu-option
slot can be used to set up custom option content and formatting.
<template>
<div>
<cdx-lookup
v-model="selection"
class="vp-lookup-custom-option"
:options="menuOptions"
@new-input="onInput"
>
<template #menu-option="{ option }">
<p class="vp-lookup-custom-option__label">
{{ option.label || option.value }}
</p>
<p v-if="option.description" class="vp-lookup-custom-option__description">
{{ option.description }}
</p>
</template>
</cdx-lookup>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CdxLookup } from 'vue-components/src/lib';
import { MenuOption } from 'vue-components/src/types';
import vegetableItems from './data';
export default defineComponent( {
name: 'LookupCustomOption',
components: { CdxLookup },
setup() {
const selection = ref( '' );
const menuOptions = ref<MenuOption[]>( [] );
function onInput( value: string ) {
if ( value ) {
menuOptions.value = vegetableItems.filter( ( item ) =>
item.label.includes( value )
);
}
}
return {
selection,
menuOptions,
onInput
};
}
} );
</script>
<style lang="less">
.vp-lookup-custom-option {
p {
margin: 0;
}
&__label {
font-weight: bold;
}
&__description {
font-size: 0.875em;
line-height: 1.25;
}
}
</style>
The footer
slot can be used to display non-interactive content below the final option. For example, a "no result found" message can be conditionally displayed.
<template>
<div>
<cdx-lookup
v-model="selection"
:options="menuOptions"
@new-input="onInput"
>
<template v-if="noResults" #footer>
No results found.
</template>
</cdx-lookup>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CdxLookup } from 'vue-components/src/lib';
import { MenuOption } from 'vue-components/src/types';
import vegetableItems from './data';
export default defineComponent( {
name: 'LookupDefault',
components: { CdxLookup },
setup() {
const selection = ref( '' );
const menuOptions = ref<MenuOption[]>( [] );
const noResults = ref( false );
function onInput( value: string ) {
if ( value ) {
menuOptions.value = vegetableItems.filter( ( item ) =>
item.label.includes( value )
);
noResults.value = menuOptions.value.length === 0;
} else {
noResults.value = false;
}
}
return {
selection,
menuOptions,
noResults,
onInput
};
}
} );
</script>
Clearable, with start icon
Props of the TextInput component can be bound to Lookup and will be passed down to the TextInput component inside of it, so you can take advantage of features like the "clear" button and icons.
<template>
<div>
<cdx-lookup
v-model="selection"
:options="menuOptions"
:clearable="true"
:start-icon="cdxIconSearch"
@new-input="onInput"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CdxLookup } from 'vue-components/src/lib';
import { MenuOption } from 'vue-components/src/types';
import { cdxIconSearch } from 'icons';
import vegetableItems from './data';
export default defineComponent( {
name: 'LookupClearableStartIcon',
components: { CdxLookup },
setup() {
const selection = ref( '' );
const menuOptions = ref<MenuOption[]>( [] );
function onInput( value: string ) {
if ( value ) {
menuOptions.value = vegetableItems.filter( ( item ) =>
item.label.includes( value )
);
}
}
return {
selection,
menuOptions,
onInput,
cdxIconSearch
};
}
} );
</script>
With placeholder
Attributes (except for class
) will fall through to the input element, so you can set things like placeholder
on the Lookup component and they'll be applied to the input.
<template>
<div>
<cdx-lookup
v-model="selection"
:options="menuOptions"
placeholder="Start typing a vegetable name..."
@new-input="onInput"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CdxLookup } from 'vue-components/src/lib';
import { MenuOption } from 'vue-components/src/types';
import vegetableItems from './data';
export default defineComponent( {
name: 'LookupWithPlaceholder',
components: { CdxLookup },
setup() {
const selection = ref( '' );
const menuOptions = ref<MenuOption[]>( [] );
function onInput( value: string ) {
if ( value ) {
menuOptions.value = vegetableItems.filter( ( item ) =>
item.label.includes( value )
);
}
}
return {
selection,
menuOptions,
onInput
};
}
} );
</script>
Usage
Props
Prop name | Description | Type | Values | Default |
---|
modelValue | Value of the selection provided by v-model binding in the parent component. | string|number|null | - | |
options | Menu options. | MenuOption[] | - | () => [] |
initialInputValue | Initial value of the text input. | string|number | - | '' |
disabled | Whether the entire component is disabled. | boolean | - | false |
Events
Event name | Properties | Description |
---|
update:modelValue | value string | number - The new value | When the selected value changes. |
new-input | value string | number - The new value | When the text input value changes. |
Slots
Name | Description | Bindings |
---|
menu-option | Display of an individual option in the menu | option MenuOption - The current option |
footer | Content to display at the end of the options list | |