What Works
Hi, I have an issue with my custom HTML dropdown made in Svelte. I'm a React engineer and new to svelte due to this company code that this small portion was written in just because previous from previous devs.
The initial click to open, handleSelection, and clickOutside, work.
What Doesn't Work
When the dropdown is open, the user should be able to click the dropdown box (class="select") and the dropdown should close. It doesn't close. Thanks in advance!
inputSelect.svelte
<svelte:options tag="input-select" />
<script lang="ts">
import { onMount } from "svelte";
import { get_current_component } from "svelte/internal";
import Button from "./button.svelte";
export let options = [];
let selectedOption = null;
let isOpen = false;
let parent: HTMLElement;
const component = get_current_component();
function openDropdown(event: MouseEvent): void {
console.log("openDropdown");
isOpen = !isOpen;
console.log("");
}
function handleSelection(value: string, event: Event): void {
console.log("HANDLE SELECTION");
selectedOption = value;
component?.dispatchEvent(
new CustomEvent("selectedOptionChanged", { detail: value })
);
console.log("HANDLE SELECTION");
console.log("");
}
function clickOutside(node: HTMLElement) {
const handleClick = (event: MouseEvent) => {
if (
node &&
!node.contains(event.target as Node) &&
isOpen === true
) {
console.log("CLICK OUTSIDE");
isOpen = false;
console.log("");
}
};
document.addEventListener("click", handleClick, true);
return {
destroy() {
document.removeEventListener("click", handleClick, true);
},
};
}
onMount(() => {
clickOutside(parent);
});
</script>
<div>
<div
class="custom-select"
style="border-color: {isOpen ? '#1677ff' : 'rgba(0, 0, 0, 0.25)'};"
>
<label
for="entity-type"
style="display: block; font-weight: 1000; margin-bottom: 4px;"
>
Entity Type {isOpen}
</label>
<div>
<div
class="select"
class:select-arrow-active={isOpen}
on:click={openDropdown}
use:clickOutside
bind:this={parent}
>
{#if selectedOption === null}
<div>Select</div>
{:else}
<div>
{options.find(
(option) => option.value === selectedOption
)?.label}
</div>
{/if}
<div
class="select-items"
style={isOpen ? "display: block;" : "display: none;"}
>
{#each options as option (option.value)}
<div
on:click={(event) => {
handleSelection(option.value, event);
event.stopPropagation();
}}
>
{option.label}
</div>
{/each}
</div>
</div>
</div>
</div>
</div>
<style lang="scss">
.custom-select {
position: relative;
width: 200px;
.select {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
border: 1px solid rgba(0, 0, 0, 0.25);
cursor: pointer;
user-select: none;
border-radius: 4px;
position: relative;
&:after {
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 4px 4px 0 4px;
border-color: rgba(0, 0, 0, 0.25) transparent transparent
transparent;
position: relative;
transform: translateY(-50%) rotate(-180deg);
margin-left: 8px;
transition: transform 0.3s ease;
}
&.select-arrow-active::after,
&.select-arrow-active::before {
transform: translateY(-50%) rotate(0deg);
}
}
.select-items {
position: absolute;
background-color: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
top: 100%;
left: 0;
right: 0;
background-color: #ffffff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 100;
}
.select-items div:hover {
background-color: #bae0ff;
color: #222222;
font-weight: 600;
font-size: 12px;
}
.select-items div {
padding: 8px 15px;
cursor: pointer;
}
.select-items div:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.select-items div:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.select-items div:first-child:hover {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.select-items div:last-child:hover {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
}
</style>
What Logs To The Console
- Initial Click to open dropdown
openDropdown
- Dropdown is open, now I click the select box.
CLICK OUTSIDE
openDropdown
Seems like the problem is that
openDropdown()is called also when you click "outside". I imagine an easy fix is to callevent.stopPropagation()inhandleClick()(inside theif).