Skip to content

Fix MultiSelect not working in label elements#1922

Merged
shinokada merged 2 commits intothemesberg:mainfrom
aarondoet:patch-1
Mar 26, 2026
Merged

Fix MultiSelect not working in label elements#1922
shinokada merged 2 commits intothemesberg:mainfrom
aarondoet:patch-1

Conversation

@aarondoet
Copy link
Copy Markdown
Contributor

@aarondoet aarondoet commented Feb 18, 2026

📑 Description

Currently the MultiSelect dropdown does not show when it is inside of a label. Or rather, it gets shown and immediately hidden again. Calling preventDefault on the onclick event fixes this.


🔍 PR Type

  • Bug fix
  • Feature
  • Documentation
  • Refactor / Code cleanup
  • Build / Tooling
  • Other (please describe)

🚦 PR Status

  • Draft (work in progress, not ready for review)
  • Ready for review ✅

✅ Checklist

  • My code follows the existing code style
  • I have run pnpm lint && pnpm check && pnpm test:e2e and all tests pass
  • CoderabbitAI review has been completed and actionable suggestions were reviewed
  • I have updated documentation if my changes require it
  • My PR is based on the latest main branch (not the published npm version)
  • I have checked accessibility where applicable (ARIA, keyboard nav, etc.)
  • I have reviewed the rendered component in the browser

⚠️ Breaking Changes (optional)

I don't think anything breaks. If anything, then that the MultiSelect id prop is added to the select and not the wrapping div anymore.


ℹ️ Additional Information

I have tested a few things.

<!-- 1. MultiSelect alone -->
<MultiSelect {...props} />

<!-- 2. MultiSelect inside of label -->
<Label>
  My Label
  <MultiSelect {...props} />
</Label>

<!-- 3. MultiSelect with external label -->
<Label for="my-multiselect">My Label</Label>
<MultiSelect id="my-multiselect" {...props} />

Cases 1 and 3 work with the current version of flowbite-svelte, but case 3 does not open the dropdown when the label is clicked.

With only event.preventDefault() all cases work, case 2 and 3 behave the same: the dropdown does not get shown when the label itself is clicked.

  const toggleDropdown = (event: MouseEvent) => {
    if (disabled) return;
    // Prevent immediate closing if the click originated from within the component itself
    // This is useful if the click triggers a re-render and focus is lost momentarily.
    if (multiSelectContainer && multiSelectContainer.contains(event.target as Node)) {
      show = !show;
+      event.preventDefault();
    } else {
      show = false; // Close if clicked outside
    }
  };

When also moving the hidden select element inside on the MultiSelect div wrapper element, case 2 works and it opens the dropdown when the label is clicked. Case 3 however stays unaffected.

-<select {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
-  {#each items as item (item.value)}
-    <option value={item.value} disabled={item.disabled}>{item.name}</option>
- {/each}
-</select>
-
<div
  bind:this={multiSelectContainer}
  {...restProps}
  onclick={toggleDropdown}
  onblur={handleBlur}
  onkeydown={handleKeyDown}
  tabindex="0"
  role="listbox"
  class={base({ size, class: clsx(theme?.base, className) })}
>
+  <select {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
+    {#each items as item (item.value)}
+      <option value={item.value} disabled={item.disabled}>{item.name}</option>
+    {/each}
+  </select>
+
  {#if !selectItems.length}
    <span class={placeholderSpan({ class: clsx(classes?.placeholder) })}>{placeholder}</span>
  {/if}

If we additionally add the restProps.id property to the hidden select, so that clicking the label is a click on the select again, then all cases work and in both case 2 and 3 the dropdown shows when clicking the label.

<script>
[...]
  let {
    children,
    items = [],
    value = $bindable(),
[...]
    // Extract select-specific props
+    id,
    name,
    form,
    required,
    autocomplete,
    ...restProps
  }: MultiSelectProps<T> = $props();
[...]
</script>

[...]

<div
  bind:this={multiSelectContainer}
  {...restProps}
  onclick={toggleDropdown}
  onblur={handleBlur}
  onkeydown={handleKeyDown}
  tabindex="0"
  role="listbox"
  class={base({ size, class: clsx(theme?.base, className) })}
>
-  <select {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
+  <select {id} {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
    {#each items as item (item.value)}
      <option value={item.value} disabled={item.disabled}>{item.name}</option>
    {/each}
  </select>

  {#if !selectItems.length}
    <span class={placeholderSpan({ class: clsx(classes?.placeholder) })}>{placeholder}</span>
  {/if}

Summary by CodeRabbit

Release Notes

  • New Features

    • MultiSelect component now accepts an id prop.
  • Bug Fixes

    • Fixed dropdown toggle behavior that could trigger unintended actions.
    • Improved internal structure of the select element for better consistency.

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 18, 2026

@aarondoet is attempting to deploy a commit to the Bergside Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

The MultiSelect component in Svelte was enhanced with a new public id prop and improved event handling. The hidden select element was restructured to render within the listbox markup instead of outside the main container. Additionally, a preventDefault() call was introduced during dropdown toggling to manage default browser behavior.

Changes

Cohort / File(s) Summary
MultiSelect Component Enhancement
src/lib/forms/select/MultiSelect.svelte
Added public id prop and passed it to hidden select element. Implemented preventDefault() during dropdown toggle. Relocated hidden select element from outside main container to within listbox markup.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • PR #1431: Both PRs address unwanted dropdown behavior in MultiSelect by modifying event handling—this PR adds preventDefault() while the related PR uses click modifiers (|self) to prevent child interactions from triggering dropdown state changes.

Poem

🐰 A little id to claim its own,
preventDefault's now well-known,
The hidden select finds its new home,
Within the listbox it shall roam! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: resolving the issue where MultiSelect dropdown doesn't work when placed inside label elements, which is the core problem addressed in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description includes a detailed explanation of the bug, the fix applied, test cases, and additional context about the changes made.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/lib/forms/select/MultiSelect.svelte (1)

122-132: else branch in toggleDropdown is dead code (pre-existing)

Since toggleDropdown is bound as onclick on multiSelectContainer, every click event that reaches it has necessarily bubbled from within (or on) the container, so multiSelectContainer.contains(event.target as Node) is always true. The else { show = false } branch is unreachable, and its comment "Close if clicked outside" is misleading — the onMount global listener (lines 194–203) already covers that case.

🧹 Optional cleanup
  const toggleDropdown = (event: MouseEvent) => {
    if (disabled) return;
-   // Prevent immediate closing if the click originated from within the component itself
-   // This is useful if the click triggers a re-render and focus is lost momentarily.
-   if (multiSelectContainer && multiSelectContainer.contains(event.target as Node)) {
-     show = !show;
-     event.preventDefault();
-   } else {
-     show = false; // Close if clicked outside
-   }
+   show = !show;
+   event.preventDefault();
  };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/forms/select/MultiSelect.svelte` around lines 122 - 132, The else
branch in the toggleDropdown function is unreachable because toggleDropdown is
only bound to clicks on multiSelectContainer; remove the dead else { show =
false } branch and its misleading comment, leaving toggleDropdown to only toggle
show (and call event.preventDefault()) when
multiSelectContainer.contains(event.target as Node) is true; rely on the
existing onMount global click listener to handle outside clicks. Update
references inside the toggleDropdown function (multiSelectContainer, show,
event) accordingly and remove the misleading comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/forms/select/MultiSelect.svelte`:
- Line 27: The id prop was pulled out and only applied to the hidden <select>,
breaking root targeting and label associations; restore the user-provided id on
the root <div> (the component root in MultiSelect.svelte) and apply a derived
select id for the hidden native select (e.g., const selectId = id ?
`${id}-select` : generatedInternalId) so the hidden <select> uses selectId while
the root <div> retains the original id; update any references to use selectId
for <label for> and ensure the hidden select id is unique when id is absent.
- Around line 219-223: Remove the `hidden` attribute from the <select> in
MultiSelect.svelte and replace it with an accessible, interactive hiding
technique so label activation works across browsers; locate the <select {id}
{name} {form} {required} {autocomplete} {value} multiple {onchange}> element in
the MultiSelect component and remove `hidden`, then apply a CSS class (or inline
styles) that hides visually but keeps the control in the accessibility and
layout tree (e.g., visibility: hidden; position: absolute; width: 0; height: 0;
or opacity: 0; position: absolute;). Ensure the new style preserves
interactivity so <label for={id}> triggers the select reliably across
Chrome/Firefox/Safari.

---

Nitpick comments:
In `@src/lib/forms/select/MultiSelect.svelte`:
- Around line 122-132: The else branch in the toggleDropdown function is
unreachable because toggleDropdown is only bound to clicks on
multiSelectContainer; remove the dead else { show = false } branch and its
misleading comment, leaving toggleDropdown to only toggle show (and call
event.preventDefault()) when multiSelectContainer.contains(event.target as Node)
is true; rely on the existing onMount global click listener to handle outside
clicks. Update references inside the toggleDropdown function
(multiSelectContainer, show, event) accordingly and remove the misleading
comment.

class: className,
classes,
// Extract select-specific props
id,
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find MultiSelectProps type definition
fd -e ts -e svelte . -path "*/forms/select/*" | head -20

Repository: themesberg/flowbite-svelte

Length of output: 238


🏁 Script executed:

# Search for MultiSelectProps definition
rg -n "interface MultiSelectProps|type MultiSelectProps" --type ts --type svelte -A 30

Repository: themesberg/flowbite-svelte

Length of output: 100


🏁 Script executed:

# Check the current MultiSelect.svelte file structure around line 27 and 211
fd -e svelte . -path "*MultiSelect.svelte" -exec cat -n {} \; | head -250

Repository: themesberg/flowbite-svelte

Length of output: 238


🏁 Script executed:

#!/bin/bash
# Find MultiSelectProps type definition - search in ts files only
rg "interface MultiSelectProps|type MultiSelectProps" -A 30

Repository: themesberg/flowbite-svelte

Length of output: 1703


🏁 Script executed:

#!/bin/bash
# Find and read the MultiSelect.svelte file
find . -name "MultiSelect.svelte" -type f | head -1

Repository: themesberg/flowbite-svelte

Length of output: 111


🏁 Script executed:

#!/bin/bash
# Read the MultiSelect.svelte file to check line 27 and surrounding context
cat -n src/lib/forms/select/MultiSelect.svelte | head -150

Repository: themesberg/flowbite-svelte

Length of output: 5477


🏁 Script executed:

#!/bin/bash
# Verify the full context around line 211 and 219 where id is used
sed -n '200,230p' src/lib/forms/select/MultiSelect.svelte | cat -n

Repository: themesberg/flowbite-svelte

Length of output: 1291


🏁 Script executed:

#!/bin/bash
# Check if there are any tests or documentation about id usage
find . -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "MultiSelect" 2>/dev/null | head -5
rg "MultiSelect.*id" --type=svelte -B 2 -A 2

Repository: themesberg/flowbite-svelte

Length of output: 100


🏁 Script executed:

#!/bin/bash
# Read more context around lines 122-132 to verify the toggleDropdown function
sed -n '120,135p' src/lib/forms/select/MultiSelect.svelte | cat -n

Repository: themesberg/flowbite-svelte

Length of output: 788


🏁 Script executed:

#!/bin/bash
# Check git history or any CHANGELOG to see if this was a documented breaking change
find . -name "CHANGELOG*" -o -name "RELEASE*" -o -name "HISTORY*" | head -3
rg "id.*breaking|breaking.*id" -i

Repository: themesberg/flowbite-svelte

Length of output: 572


🏁 Script executed:

#!/bin/bash
# Check if there are example usages or tests that show how id was previously used
rg "MultiSelect" -A 10 -B 2 | grep -A 10 -B 2 "id=" | head -40

Repository: themesberg/flowbite-svelte

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check CHANGELOG to see if there are any mentions of this PR or MultiSelect changes
cat CHANGELOG.md | head -100

Repository: themesberg/flowbite-svelte

Length of output: 2488


🏁 Script executed:

#!/bin/bash
# Check if there's documentation about how id should be used with MultiSelect
find . -name "*.md" | xargs grep -l "MultiSelect" | head -3

Repository: themesberg/flowbite-svelte

Length of output: 156


🏁 Script executed:

#!/bin/bash
# Check the forms/select documentation for MultiSelect usage examples
cat src/routes/docs/forms/select.md | head -200

Repository: themesberg/flowbite-svelte

Length of output: 4231


🏁 Script executed:

#!/bin/bash
# Check for any examples with MultiSelect and id attribute
find src/routes -name "*.svelte" | xargs grep -l "MultiSelect" | head -5

Repository: themesberg/flowbite-svelte

Length of output: 674


🏁 Script executed:

#!/bin/bash
# Look for actual example files
find src/routes/docs -name "Multi*.svelte" | head -10

Repository: themesberg/flowbite-svelte

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check MultiSelect examples for id usage
cat src/routes/docs-examples/forms/select/Multi.svelte

Repository: themesberg/flowbite-svelte

Length of output: 467


id prop moved to hidden select breaks root element targeting — breaking change

The id prop was previously implicitly part of MultiSelectProps via HTMLAttributes<HTMLDivElement> and flowed through restProps to the root <div>. After extracting id explicitly (line 27) and applying it only to the hidden <select> (line 219), the root element no longer receives the user-provided id.

This breaks:

  • CSS selectors: #my-select { ... } targets the hidden select, not the component root
  • DOM APIs: document.getElementById('my-select') returns a display:none element
  • Accessibility: aria-labelledby or aria-describedby referencing the component id will fail

Additionally, the hidden <select> has the hidden attribute, which removes it from the accessibility tree. This breaks <label for> associations since labels require a focusable, semantically present form control.

Restore the id to the root <div> and use a derived id (e.g., ${id}-select) for the hidden select, or use $props.id() to generate a separate internal id for the select if no external id is provided.

Proposed fix
  let {
    children,
    items = [],
    value = $bindable(),
    size = "md",
    dropdownClass = "",
    placeholder = "",
    disabled = false,
    onchange,
    onblur,
    class: className,
    classes,
    // Extract select-specific props
    id,
    name,
    form,
    required,
    autocomplete,
    ...restProps
  }: MultiSelectProps<T> = $props();
+ let internalSelectId = $derived(id ? `${id}-select` : undefined);
- <select {id} {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
+ <select id={internalSelectId} {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
  <div
    bind:this={multiSelectContainer}
-   {...restProps}
+   id={id}
+   {...restProps}
    onclick={toggleDropdown}
    onblur={handleBlur}
    onkeydown={handleKeyDown}
    tabindex="0"
    role="listbox"
    class={base({ size, class: clsx(theme?.base, className) })}
  >

Document that for <label for> associations, consumers should target the derived selectId prop or use for="${id}-select".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/forms/select/MultiSelect.svelte` at line 27, The id prop was pulled
out and only applied to the hidden <select>, breaking root targeting and label
associations; restore the user-provided id on the root <div> (the component root
in MultiSelect.svelte) and apply a derived select id for the hidden native
select (e.g., const selectId = id ? `${id}-select` : generatedInternalId) so the
hidden <select> uses selectId while the root <div> retains the original id;
update any references to use selectId for <label for> and ensure the hidden
select id is unique when id is absent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the id being on the select instead of the div breaks anything. Library users should never style the element via the id, rather via classes or snippets. The library itself does not use the id. The only reason for using an id that I see is exactly what I fixed here, labeling the element, and for that the id needs to be on the select.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🌐 Web query:

HTML label for attribute with hidden form control accessibility

💡 Result:

  • If the control is truly hidden (e.g., <input type="hidden"> or hidden via display:none/hidden), don’t use <label for="…"> for accessibility—it won’t be a “labelable” control, isn’t focusable, and is effectively not exposed to assistive tech. Hidden inputs specifically are not labelable and input.labels becomes null when type="hidden". [1], [2], [3], [4]
  • If you mean “visually hidden but still accessible” (screen-reader-only), keep it labelable (e.g., type="text", type="checkbox", etc.), hide it with “visually-hidden” CSS (not display:none), and a normal <label for="id">…</label> works. (The key is: it must remain rendered/available to the accessibility tree.) [4]
  • If you have no visible label you can associate, give the control an accessible name with aria-labelledby (preferred when label text exists in the DOM) or aria-label. [5]

@aarondoet, I understand your reasoning about styling practices, and you're right that the library doesn't internally reference the id. However, there's an accessibility concern with placing the id on the hidden select:

According to accessibility specifications, hidden form controls (using the hidden attribute or display:none) are not labelable elements and are removed from the accessibility tree. This means:

  1. Screen readers won't announce the label association - while a <label for="my-id"> pointing to the hidden select may trigger click behavior visually, assistive technology won't expose this relationship to users
  2. The hidden select is not focusable or accessible - it's effectively invisible to AT users
  3. The root <div> with role="listbox" is the actual accessible control - this is what screen readers interact with

For proper accessibility, the id should remain on the root <div> so that:

  • aria-labelledby or aria-describedby can reference it
  • Screen readers can properly announce the component when focused
  • The accessible control (the listbox) has the identity, not the hidden implementation detail

The visual label-click behavior you're fixing works due to the preventDefault() logic you added, which is great! But the accessibility association requires the id on the accessible element (the root div), not the hidden select.

Would you be open to applying the id to the root div and using a derived id (like ${id}-select) for the hidden select if needed for form submission purposes?


🧠 Learnings used
Learnt from: jjagielka
Repo: themesberg/flowbite-svelte PR: 1822
File: src/lib/command-palette/CommandPalette.svelte:30-31
Timestamp: 2025-11-04T14:50:28.736Z
Learning: In Svelte 5.20.0+, `$props.id()` is a valid rune that generates a unique ID for the current component instance. The syntax `let gid = $props.id();` is correct and commonly used for creating unique IDs for accessibility attributes like `aria-controls`, `aria-labelledby`, etc.

Learnt from: LahTeuto
Repo: themesberg/flowbite-svelte PR: 1484
File: src/lib/navbar/NavLi.svelte:34-34
Timestamp: 2024-11-12T10:36:34.807Z
Learning: When enhancing ARIA roles in Svelte components, avoid setting `role="presentation"` on elements that should retain the `link` role, as it can diminish ARIA role coverage and negatively affect accessibility.

Learnt from: mrh1997
Repo: themesberg/flowbite-svelte PR: 1442
File: src/lib/utils/Popper.svelte:144-145
Timestamp: 2024-11-22T08:37:27.996Z
Learning: In `src/lib/utils/Popper.svelte`, inconsistencies in event handling (e.g., using both `mouseenter`/`mouseleave` and `pointerenter`/`pointerleave`) may be intentional to minimize modifications and reduce the risk of new problems.

Comment on lines +219 to +223
<select {id} {name} {form} {required} {autocomplete} {value} hidden multiple {onchange}>
{#each items as item (item.value)}
<option value={item.value} disabled={item.disabled}>{item.name}</option>
{/each}
</select>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does clicking label for dispatch click to hidden form element Chrome Firefox Safari HTML behavior

💡 Result:

  • Yes—usually. In HTML, a <label> can be associated with a labelable form control (via for/id or by nesting). When the label is activated, browsers typically perform label activation by firing a separate click at the associated control (it’s not “bubbling” the same click from the label to the input). The exact platform behavior is described as matching the platform’s label behavior, but “fire a click event at the input” is explicitly called out as the typical case. [1]
  • But not for truly “hidden” controls:
    • <input type="hidden"> is not labelable, so a label can’t activate it. (In the spec, labels is null for inputs whose type is in the Hidden state.) [1]
    • Elements hidden with the hidden attribute also shouldn’t be referenced by label for=... (authoring requirement). [2]
  • If it’s only “hidden” via CSS (display:none, etc.) the control is still the labeled control (because it’s still labelable), but browser behavior can differ for some control types, especially file inputs: Safari has long had cases where a label won’t open a file picker if the associated <input type="file"> is display:none, while other browsers may allow it. [3]
  • Practical implication for events: if you’re testing “does it dispatch click to the hidden form element,” attach a click (or better, for checkboxes/radios, change) handler to the control itself—don’t expect the label’s click to have event.target === input. [1][4]

Sources: HTML Standard (label element) [1], HTML Standard (hidden attribute + label for restriction) [2], Safari + hidden file input via label (Stack Overflow) [3], MDN <label> reference [4].


Remove hidden attribute from <select> — violates HTML spec and breaks cross-browser label activation

The HTML specification explicitly discourages using <label for> with elements that have the hidden attribute. Additionally, web testing confirms that when a hidden form control (via display:none) is targeted by <label for>, the browser's synthetic click dispatch is unreliable across Chrome, Firefox, and Safari—Safari in particular is known to silently fail to activate hidden form controls when clicked via their associated label.

Replace the hidden attribute with one of these accessible alternatives:

  • visibility: hidden; position: absolute; width: 0; height: 0; — keeps element in layout tree, can receive focus/clicks programmatically, hidden from view
  • opacity: 0; position: absolute; — similar effect, element remains interactive

This ensures the <label for> interaction works reliably across all browsers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/forms/select/MultiSelect.svelte` around lines 219 - 223, Remove the
`hidden` attribute from the <select> in MultiSelect.svelte and replace it with
an accessible, interactive hiding technique so label activation works across
browsers; locate the <select {id} {name} {form} {required} {autocomplete}
{value} multiple {onchange}> element in the MultiSelect component and remove
`hidden`, then apply a CSS class (or inline styles) that hides visually but
keeps the control in the accessibility and layout tree (e.g., visibility:
hidden; position: absolute; width: 0; height: 0; or opacity: 0; position:
absolute;). Ensure the new style preserves interactivity so <label for={id}>
triggers the select reliably across Chrome/Firefox/Safari.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested the behavior in Firefox where the select was clicked via the label despite being hidden.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aarondoet, thank you for testing! Firefox is good news. My concern was primarily about Safari, which the web research flagged as sometimes failing to activate hidden form controls via label clicks (though that was specifically documented for file inputs, not select elements).

Have you had a chance to test in Safari as well? If it works there too, then your real-world testing trumps the theoretical concern, and the current implementation is fine.


🧠 Learnings used
Learnt from: mrh1997
Repo: themesberg/flowbite-svelte PR: 1442
File: src/lib/utils/Popper.svelte:144-145
Timestamp: 2024-11-22T08:37:27.996Z
Learning: In `src/lib/utils/Popper.svelte`, inconsistencies in event handling (e.g., using both `mouseenter`/`mouseleave` and `pointerenter`/`pointerleave`) may be intentional to minimize modifications and reduce the risk of new problems.

Learnt from: LahTeuto
Repo: themesberg/flowbite-svelte PR: 1484
File: src/lib/navbar/NavLi.svelte:34-34
Timestamp: 2024-11-12T10:36:34.807Z
Learning: When enhancing ARIA roles in Svelte components, avoid setting `role="presentation"` on elements that should retain the `link` role, as it can diminish ARIA role coverage and negatively affect accessibility.

@aarondoet
Copy link
Copy Markdown
Contributor Author

If the accessibility concerns raised by code rabbit are true (as said, I'm testing on Firefox, and without screen reader, for me everything works as intended), then everything except for the event.preventDefault() can be scrapped, but at least keep that so that MultiSelect works at all in labels.

@shinokada shinokada merged commit 85d679d into themesberg:main Mar 26, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants