← Work

Select multiple items with Svelte

Updated 1 minute ago

I ran into a tricky problem for a client recently in a Svelte project.

They wanted to select multiple photos on the screen then tag those items all at the same time.

What we settled on was holding control and clicking on a photo to select it.

This is something similar.

Detecting keyups and downs

We have to detect when control is held and not held. To do so with Svelte you could do something like this.

 let selectedPhotos = [];
 let controlPressed = false;
 function handleKeydown(event) {
    console.log(event.key);
    if (event.key === "Control") {
      controlPressed = true;
    }
  }
 function handleKeyup(event) {
    controlPressed = false;
 }

We'll throw selected photos into the selectedPhotos array soon.

I added a little smiley face up in the corner to show when Control is held 😀.

Detecting clicks on photos

We need to run this every time a photo is clicked but only do something when control is held.

  function handlePhotoSelect(photoId) {
    if (controlPressed) {
      if (selectedPhotos.includes(photoId)) {
        selectedPhotos = selectedPhotos.filter(photo => photo !== photoId);
      } else {
        selectedPhotos = [...selectedPhotos, photoId];
      }
    }
  }

With Svelte, you need to reassign selectedPhotos otherwise Svelte doesn't know to rerender that DOM node.

Les styles and <main>

This should be pretty straightforward.

<svelte:window on:keydown={handleKeydown} on:keyup={handleKeyup} />

<main>
	<h1>Hello Svelter</h1>
  {#if controlPressed}
    <div class="smiley" transition:fade>
    😀
    </div>
  {/if}
  <div class="pics">
  {#each photos as photo, i}
  <img on:click={() => handlePhotoSelect(photo)} class:selected={selectedPhotos.includes(photo)} src={photo} alt={i} />
  {/each}
  </div>
</main>

<style>
  main {
    font-family: sans-serif;
    text-align: center;
    position: relative;
  }
  .smiley {
    font-size: 2rem;
    position: absolute;
    top: 0;
    right: 0;
  }
  .pics {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(3, 1fr);
  }
  img {
    object-fit: cover;
    width: 100%;
  }
  .selected {
    box-shadow: 0px 12px 22px 1px #333;
  }
</style>

The first step is to listen on the Window for keydowns and ups. Svelte has a handy window element which is completely underrated. I use it a lot.

Next we iterate over our pictures. You do you, I did food.

Then we style it all and call it quits.

Let me know what you think 🤔.

You can see the sandbox here https://codesandbox.io/s/svelte-multiple-photo-select-ff21m?file=/App.svelte:1609-2390