svelte-selected v4.4.5
svelte-selected
This is a convenience fork of svelte-select component. All other credits go to the original author.
A select/autocomplete component for Svelte apps. With support for grouping, filtering, async and more.
Changes in this fork include:
- added new prop
keepOpento keep the options open when isisMultiset to true. - added several css properties for better css framework integration.
Installation
pnpm install svelte-selectedNote: Install as a dev dependency (yarn add svelte-select --dev) if using Sapper to avoid a SSR error.
Usage
<script>
import Select from 'svelte-select';
let items = [
{value: 'chocolate', label: 'Chocolate'},
{value: 'pizza', label: 'Pizza'},
{value: 'cake', label: 'Cake'},
{value: 'chips', label: 'Chips'},
{value: 'ice-cream', label: 'Ice Cream'},
];
let value = {value: 'cake', label: 'Cake'};
function handleSelect(event) {
console.log('selected item', event.detail);
// .. do something here 🙂
}
</script>
<Select {items} {value} on:select={handleSelect}></Select>API
id: StringDefault:null. Add an id to the input field.items: ArrayDefault:[]. List of selectable items that appear in the dropdown.value: AnyDefault:null. Selected item or items.filterText: StringDefault:''. Text to filteritemsby.placeholder: StringDefault:'Select...'. Placeholder text.noOptionsMessage: StringDefault:'No options'. Message to display in list when there are noitems.optionIdentifier: StringDefault:'value'. Override default identifier.labelIdentifier: StringDefault:'label'. Override default identifier.keepOpen: BooleanDefault:falseKeep list open until nothing is left, when inisMultiset to true.listOpen: BooleanDefault:false. Open/close list.hideEmptyState: BooleanDefault:false. Hide list and don't shownoOptionsMessagewhen there are noitems.containerClasses: StringDefault:''. Add extra container classes, for example 'global-x local-y'.containerStyles: StringDefault:''. Add inline styles to container.isClearable: BooleanDefault:true. Enable clearing of selected items.isCreatable: BooleanDefault:false. Can create new item(s) to be added tovalue.isDisabled: BooleanDefault:false. Disable select.isMulti: BooleanDefault:false. Enable multi-select,valuebecomes an array of selected items.isSearchable: BooleanDefault:true. Enable search/filtering ofitemsviafilterText.isGroupHeaderSelectable: BooleanDefault:false. Enable selectable group headers initems(see adv demo).listPlacement: StringDefault:'auto'. When'auto'displays either'top'or'bottom'depending on viewport.hasError: BooleanDefault:false. Show/hide error styles around select input (red border by default).listAutoWidth: BooleanDefault:true. List width will grow wider than the Select container (depending on list item content length).showIndicator: BooleanDefault:false. If true, the chevron indicator is always shown.inputAttributes: ObjectDefault:{}. Pass in HTML attributes to the Select input.Item: ComponentDefault:Item. Item component.Selection: ComponentDefault:Selection. Selection component.MultiSelection: ComponentDefault:MultiSelection. Multi selection component.Icon: ComponentDefault:Icon. Icon component.iconProps: ObjectDefault:{}. Icon props.indicatorSvg: @htmlDefault:undefined. Override default SVG chevron indicator.ClearIconDefault:ClearIcon. ClearIcon component.isVirtualList: BooleanDefault:false. Uses svelte-virtual-list to render list (experimental).filteredItems: ArrayDefault:[]. List of items that are filtered byfilterTextplaceholderAlwaysShow: BooleanDefault:false. WhenisMultithen placeholder text will always still show.isWaiting: BooleanDefault:false. If true then loader shows.loadOptionswill automatically set this as true until promise resolves.listOffset: NumberDefault:5. Controls the spacing offset between the list and the input.
Items
items can be simple arrays or collections.
<script>
import Select from 'svelte-select';
let simple = ['one', 'two', 'three'];
let collection = [
{ value: 1, label: 'one' },
{ value: 2, label: 'two' },
{ value: 3, label: 'three' },
];
</script>
<Select items={simple} />
<Select items={collection} />They can also be grouped and include non-selectable items.
<script>
import Select from 'svelte-select';
const items = [
{value: 'chocolate', label: 'Chocolate', group: 'Sweet'},
{value: 'pizza', label: 'Pizza', group: 'Savory'},
{value: 'cake', label: 'Cake', group: 'Sweet', selectable: false},
{value: 'chips', label: 'Chips', group: 'Savory'},
{value: 'ice-cream', label: 'Ice Cream', group: 'Sweet'}
];
const groupBy = (item) => item.group;
</script>
<Select {items} {groupBy} />You can also use custom collections.
<script>
import Select from 'svelte-select';
const optionIdentifier = 'id';
const labelIdentifier = 'title';
const items = [
{id: 0, title: 'Foo'},
{id: 1, title: 'Bar'},
];
</script>
<Select {optionIdentifier} {labelIdentifier} {items} />Async Items
To load items asynchronously then loadOptions is the simplest solution. Supply a function that returns a Promise that resolves with a list of items. loadOptions has debounce baked in and fires each time filterText is updated.
<script>
import Select from 'svelte-select';
import { someApiCall } from './services';
async function examplePromise(filterText) {
// Put your async code here...
// For example call an API using filterText as your search params
// When your API responds resolve your Promise
let res = await someApiCall(filterText);
return res;
}
</script>
<Select loadOptions={examplePromise} />Exposed methods
These internal functions are exposed to override if needed. See the adv demo or look through the test file (test/src/index.js) for examples.
export let itemFilter = (label, filterText, option) => label.toLowerCase().includes(filterText.toLowerCase());export let groupBy = undefined;export let groupFilter = groups => groups;export let createGroupHeaderItem = groupValue => {
return {
value: groupValue,
label: groupValue
};
};export let createItem = filterText => {
return {
value: filterText,
label: filterText
};
};export let getOptionLabel = (option, filterText) => {
return option.isCreator ? `Create \"${filterText}\"` : option.label;
};export let getSelectionLabel = option => {
if (option) return option.label;
};export let getGroupHeaderLabel = option => {
return option.label;
};export function handleClear() {
value = undefined;
listOpen = false;
dispatch("clear", value);
handleFocus();
}export let loadOptions = undefined; // if used must return a Promise that updates 'items'
/* Return an object with { cancelled: true } to keep the loading state as active. */export const getFilteredItems = () => {
return filteredItems;
};A11y (Accessibility)
Override these methods to change the aria-context and aria-selection text.
export let ariaValues = (values) => {
return `Option ${values}, selected.`;
}
export let ariaListOpen = (label, count) => {
return `You are currently focused on option ${label}. There are ${count} results available.`;
}
export let ariaFocused = () => {
return `Select is focused, type to refine list, press down to open the menu.`;
}Styling
You can style a component by overriding the available CSS variables.
<script>
import Select from 'svelte-select';
const items = ['One', 'Two', 'Three'];
</script>
<style>
.themed {
--border: 3px solid blue;
--borderRadius: 10px;
--placeholderColor: blue;
}
</style>
<div class="themed">
<h2>Theming</h2>
<Select {items}></Select>
</div>You can also use the inputStyles prop to write in any override styles needed for the input.
<script>
import Select from 'svelte-select';
const items = ['One', 'Two', 'Three'];
</script>
<Select {items} inputStyles="box-sizing: border-box;"></Select>Events
| Event Name | Callback | Description |
|---|---|---|
| select | { detail } | fires when value changes |
| clear | { detail } | fires when clear all is invoked or item is removed (by user) from multi select |
| loaded | { items } | fires when loadOptions resolves |
| error | { type, details } | fires when error is caught |
<script>
import Select from 'svelte-select';
let items = [...];
function handleSelect(event) {
// event.detail will contain the selected value
...
}
function handleClear(event) {
// event.detail will be null unless isMulti is true and user has removed a single item
...
}
</script>
<Select {items} on:select={handleSelect} on:clear={handleClear}></Select>Development
yarn global add serve@8
yarn
yarn dev
yarn test:browserIn your favourite browser go to http://localhost:3000 and open devtools and see the console for the test output. When developing its handy to see the component on the page; comment out the select.$destroy(); on the last test in /test/src/index.js or use the test.only() to target just one test.
For example:
test.only('when getSelectionLabel contains HTML then render the HTML', async (t) => {
const select = new Select({
target,
props: {
value: items[0],
getSelectionLabel: (option) => `<p>${option.label}</p>`,
}
});
t.ok(document.querySelector('.selection').innerHTML === '<p>Chocolate</p>');
//select.$destroy();
});Configuring webpack
If you're using webpack with svelte-loader, make sure that you add "svelte" to resolve.mainFields in your webpack config. This ensures that webpack imports the uncompiled component — this is more efficient.
If you're using Rollup with rollup-plugin-svelte, this will happen automatically.