« home

svelte-multiselect Svelte MultiSelect

Snippets

Svelte SVG component as "removeIcon" snippet

  <script>
  import MultiSelect, { Icon } from '$lib'
  import { languages } from '$site/options'
  import { LanguageSnippet, MinusIcon } from '$site'
</script>

<MultiSelect
  options={languages}
  maxSelect={5}
  placeholder="What languages do you know?"
  selected={['Python', 'TypeScript', 'Julia']}
>
  {#snippet children({ option })}
    <LanguageSnippet {option} />
  {/snippet}
  {#snippet expandIcon({ open })}
    <Icon icon={open ? 'Collapse' : 'Expand'} />
  {/snippet}
  {#snippet removeIcon()}
    <MinusIcon width="1em" />
  {/snippet}
</MultiSelect>
  1. LanguageSnippet.svelte
    <script lang="ts">
      interface Props {
        option: string
        idx?: number | undefined
        height?: string
        gap?: string
      }
      let { option, idx = undefined, height = `20px`, gap = `5pt` }: Props = $props()
    
      let lang = $derived(
        option.toLowerCase().replaceAll(`+`, `plus`).replace(`#`, `sharp`),
      )
      let src = $derived(
        `https://cdn.jsdelivr.net/gh/devicons/devicon/icons/${lang}/${lang}-original.svg`,
      )
      let hidden = $state(false)
    
      // default back to visible every time src changes to see if image loads successfully
      $effect(() => {
        if (src) hidden = false
      })
    </script>
    
    <span style:gap>
      {#if idx !== undefined}
        <strong>{idx + 1}</strong>
      {/if}
      <img {src} {height} alt={option} {hidden} onerror={() => (hidden = true)} />
      {option}
    </span>
    
    <style>
      span {
        display: flex;
      }
      img {
        transform: translateY(2px);
      }
      img[alt='Rust'] {
        filter: invert(1);
      }
    </style>
    
  2. MinusIcon.svelte
    <script lang="ts">
      import type { SVGAttributes } from 'svelte/elements'
    
      let { ...props }: SVGAttributes<EventTarget> = $props()
    </script>
    
    <svg aria-hidden="true" role="img" fill="currentColor" viewBox="0 0 24 24" {...props}>
      <path
        d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2zm4 11H8c-.55 0-1-.45-1-1s.45-1 1-1h8c.55 0 1 .45 1 1s-.45 1-1 1z"
      />
    </svg>
    

Simple HTML tag as "removeIcon" snippet

  <script>
  import MultiSelect, { Icon } from '$lib'
  import { languages } from '$site/options'
  import { LanguageSnippet } from '$site'

  // local variable used in CollapseIcon onclick callback to close dropdown
  let open = $state(false)
</script>

<MultiSelect
  options={languages}
  maxSelect={5}
  placeholder="What languages do you know?"
  selected={[`Python`, `TypeScript`, `Julia`]}
  bind:open
>
  {#snippet selectedItem({ option })}
    <LanguageSnippet {option} />
  {/snippet}
  {#snippet option({ option })}
    <LanguageSnippet {option} />
  {/snippet}
  {#snippet expandIcon({ open: expandOpen })}
    <button
      onclick={() => (open = false)}
      onkeyup={(event) => {
        event.preventDefault()
        if ([`Enter`, `Space`].includes(event.code)) open = !open
      }}
    >
      <Icon icon={expandOpen ? `Collapse` : `Expand`} />
    </button>
  {/snippet}
  {#snippet removeIcon()}
    <span style="width: 2ex">x</span>
  {/snippet}
</MultiSelect>

"user-msg" snippet

  <script>
  import MultiSelect, { Icon } from '$lib'
  import { languages } from '$site/options'
  import { LanguageSnippet } from '$site'

  let selected = $state([`Python`, `TypeScript`, `Julia`])
  let searchText = $state(`Julia`)
</script>

<MultiSelect
  options={languages}
  bind:searchText
  bind:selected
  maxSelect={5}
  placeholder="What languages do you know?"
  open
  allowUserOptions
>
  {#snippet userMsg({ msg })}
    <span>{msg} {selected?.includes(searchText) ? '🤦' : '👷'}</span>
  {/snippet}
</MultiSelect>