Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 3 additions & 26 deletions assets/js/hooks/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,42 +330,19 @@ export default {
},

setupAriaRelationships(button, menu) {
const dropdownId = this.el.id
const triggerId = button.id || `${dropdownId}-trigger`
const menuId = menu.id || `${dropdownId}-menu`
button.setAttribute('aria-controls', menu.id)
menu.setAttribute('aria-labelledby', button.id)

if (!button.id) button.id = triggerId
button.setAttribute('aria-controls', menuId)
if (!menu.id) menu.id = menuId
menu.setAttribute('aria-labelledby', triggerId)

this.setupMenuitemIds()
this.setupSectionLabels()
},

setupMenuitemIds() {
const dropdownId = this.el.id
const items = this.el.querySelectorAll(SELECTORS.MENUITEM)

items.forEach((item, index) => {
if (!item.id) {
item.id = `${dropdownId}-item-${index}`
}
})
},

setupSectionLabels() {
const dropdownId = this.el.id
const sections = this.el.querySelectorAll('[role="group"]')

sections.forEach((section, sectionIndex) => {
sections.forEach((section) => {
// Check if the first child is a heading (role="presentation")
const firstChild = section.firstElementChild
if (firstChild && firstChild.getAttribute('role') === 'presentation') {
// Ensure the heading has an ID
if (!firstChild.id) {
firstChild.id = `${dropdownId}-section-${sectionIndex}-heading`
}
// Link the section to the heading
section.setAttribute('aria-labelledby', firstChild.id)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<div>
<.dropdown id="dropdown-custom">
<.dropdown_trigger as={&custom_button/1} data-custom-attr="test-value">
<.dropdown_trigger
id="dropdown-custom-trigger"
as={&custom_button/1}
data-custom-attr="test-value"
>
Open Dropdown
</.dropdown_trigger>
<.dropdown_menu>
<.dropdown_item>
<.dropdown_menu id="dropdown-custom-menu">
<.dropdown_item id="dropdown-custom-item-0">
Regular Item
</.dropdown_item>
<.dropdown_item as={&link/1} navigate={~p"/"}>
<.dropdown_item id="dropdown-custom-item-1" as={&link/1} navigate={~p"/"}>
Link Item
</.dropdown_item>
<.dropdown_item disabled={true} as={&link/1} href="#disabled">
<.dropdown_item id="dropdown-custom-item-2" disabled={true} as={&link/1} href="#disabled">
Disabled Link
</.dropdown_item>
</.dropdown_menu>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<.dropdown_item id="my-item-2">
Banana
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-custom-ids-item-2">
Cherry
</.dropdown_item>
</.dropdown_menu>
Expand Down
12 changes: 6 additions & 6 deletions demo/lib/demo_web/live/fixtures_live/dropdown_fixture.html.heex
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<div>
<.dropdown id="dropdown">
<.dropdown_trigger>
<.dropdown_trigger id="dropdown-trigger">
Open Dropdown
</.dropdown_trigger>
<.dropdown_menu>
<.dropdown_item>
<.dropdown_menu id="dropdown-menu">
<.dropdown_item id="dropdown-item-0">
Apple
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-item-1">
Banana
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-item-2">
Cherry
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-item-3">
Apricot
</.dropdown_item>
</.dropdown_menu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div>
<.dropdown id="dropdown">
<.dropdown_trigger>
<.dropdown_trigger id="dropdown-trigger">
{@trigger_label}
</.dropdown_trigger>
<.dropdown_menu>
<.dropdown_item>
<.dropdown_menu id="dropdown-menu">
<.dropdown_item id="dropdown-item-0">
Apple
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-item-1">
Banana
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-item-2">
Cherry
</.dropdown_item>
</.dropdown_menu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
<.dropdown id="dropdown-sections">
<.dropdown_trigger as={&button/1}>
<.dropdown_trigger id="dropdown-sections-trigger" as={&button/1}>
Account Menu
</.dropdown_trigger>
<.dropdown_menu>
<.dropdown_menu id="dropdown-sections-menu">
<.dropdown_section>
<.dropdown_heading>
<.dropdown_heading id="dropdown-sections-heading-account">
Account
</.dropdown_heading>
<.dropdown_item>
<.dropdown_item id="dropdown-sections-item-0">
Profile
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-sections-item-1">
Settings
</.dropdown_item>
</.dropdown_section>

<.dropdown_separator />

<.dropdown_section>
<.dropdown_heading>
<.dropdown_heading id="dropdown-sections-heading-support">
Support
</.dropdown_heading>
<.dropdown_item>
<.dropdown_item id="dropdown-sections-item-2">
Documentation
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-sections-item-3">
Contact Us
</.dropdown_item>
</.dropdown_section>

<.dropdown_separator />

<.dropdown_item>
<.dropdown_item id="dropdown-sections-item-4">
Sign Out
</.dropdown_item>
</.dropdown_menu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div>
<.dropdown id="dropdown-with-disabled">
<.dropdown_trigger>
<.dropdown_trigger id="dropdown-with-disabled-trigger">
Open Dropdown
</.dropdown_trigger>
<.dropdown_menu>
<.dropdown_item>
<.dropdown_menu id="dropdown-with-disabled-menu">
<.dropdown_item id="dropdown-with-disabled-item-0">
Enabled Item 1
</.dropdown_item>
<.dropdown_item disabled={true}>
<.dropdown_item id="dropdown-with-disabled-item-1" disabled={true}>
Disabled Item
</.dropdown_item>
<.dropdown_item>
<.dropdown_item id="dropdown-with-disabled-item-2">
Enabled Item 2
</.dropdown_item>
</.dropdown_menu>
Expand Down
10 changes: 7 additions & 3 deletions demo/priv/code_examples/dropdown/basic.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<.dropdown id="basic-dropdown">
<.dropdown_trigger as={&button/1}>
<.dropdown_trigger id="basic-dropdown-trigger" as={&button/1}>
Open Dropdown
<svg
class="-mr-1 h-5 w-5 text-whites"
Expand All @@ -14,9 +14,13 @@
/>
</svg>
</.dropdown_trigger>
<.dropdown_menu class="w-56 py-1 rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none">
<.dropdown_menu
id="basic-dropdown-menu"
class="w-56 py-1 rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none"
>
<.dropdown_item
:for={option <- ["Account settings", "Billing", "Documentation"]}
:for={{option, index} <- Enum.with_index(["Account settings", "Billing", "Documentation"])}
id={"basic-dropdown-item-#{index}"}
class="text-gray-700 data-focus:bg-gray-100 data-focus:text-gray-900 block px-4 py-2 text-sm"
>
{option}
Expand Down
23 changes: 18 additions & 5 deletions demo/priv/code_examples/dropdown/disabled.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<.dropdown id="disabled-demo-dropdown">
<.dropdown_trigger as={&button/1}>
<.dropdown_trigger id="disabled-demo-trigger" as={&button/1}>
Open Dropdown
<svg
class="-mr-1 h-5 w-5 text-whites"
Expand All @@ -14,20 +14,33 @@
/>
</svg>
</.dropdown_trigger>
<.dropdown_menu class="w-56 py-1 rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none">
<.dropdown_item class="text-gray-700 data-focus:bg-gray-100 data-focus:text-gray-900 block px-4 py-2 text-sm">
<.dropdown_menu
id="disabled-demo-menu"
class="w-56 py-1 rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none"
>
<.dropdown_item
id="disabled-demo-item-0"
class="text-gray-700 data-focus:bg-gray-100 data-focus:text-gray-900 block px-4 py-2 text-sm"
>
Edit Profile
</.dropdown_item>
<.dropdown_item
id="disabled-demo-item-1"
disabled={true}
class="text-gray-400 data-disabled:opacity-50 block px-4 py-2 text-sm"
>
Archive (disabled)
</.dropdown_item>
<.dropdown_item class="text-gray-700 data-focus:bg-gray-100 data-focus:text-gray-900 block px-4 py-2 text-sm">
<.dropdown_item
id="disabled-demo-item-2"
class="text-gray-700 data-focus:bg-gray-100 data-focus:text-gray-900 block px-4 py-2 text-sm"
>
Settings
</.dropdown_item>
<.dropdown_item class="text-red-700 data-focus:bg-red-100 data-focus:text-red-900 block px-4 py-2 text-sm">
<.dropdown_item
id="disabled-demo-item-3"
class="text-red-700 data-focus:bg-red-100 data-focus:text-red-900 block px-4 py-2 text-sm"
>
Sign Out
</.dropdown_item>
</.dropdown_menu>
Expand Down
48 changes: 39 additions & 9 deletions demo/priv/code_examples/dropdown/positioned.html.heex
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<div class="flex space-x-8 justify-center">
<!-- Top-start placement -->
<.dropdown id="top-dropdown">
<.dropdown_trigger class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80">
<.dropdown_trigger
id="top-dropdown-trigger"
class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80"
>
Top Menu
<svg
class="-mr-1 h-5 w-5 rotate-180"
Expand All @@ -17,6 +20,7 @@
</svg>
</.dropdown_trigger>
<.dropdown_menu
id="top-dropdown-menu"
placement="top-start"
class="w-48 py-1rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none"
transition_enter={
Expand All @@ -28,18 +32,27 @@
"transform opacity-0 scale-95"}
}
>
<.dropdown_item class="text-gray-700 data-focus:bg-blue-100 data-focus:text-blue-900 block px-4 py-2 text-sm">
<.dropdown_item
id="top-dropdown-item-0"
class="text-gray-700 data-focus:bg-blue-100 data-focus:text-blue-900 block px-4 py-2 text-sm"
>
Option A
</.dropdown_item>
<.dropdown_item class="text-gray-700 data-focus:bg-blue-100 data-focus:text-blue-900 block px-4 py-2 text-sm">
<.dropdown_item
id="top-dropdown-item-1"
class="text-gray-700 data-focus:bg-blue-100 data-focus:text-blue-900 block px-4 py-2 text-sm"
>
Option B
</.dropdown_item>
</.dropdown_menu>
</.dropdown>

<!-- Right-start placement -->
<.dropdown id="right-dropdown">
<.dropdown_trigger class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80">
<.dropdown_trigger
id="right-dropdown-trigger"
class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80"
>
Right Menu
<svg class="-mr-1 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
Expand All @@ -50,6 +63,7 @@
</svg>
</.dropdown_trigger>
<.dropdown_menu
id="right-dropdown-menu"
placement="right-start"
class="w-48 py-1rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none"
transition_enter={
Expand All @@ -61,18 +75,27 @@
"transform opacity-0 scale-95"}
}
>
<.dropdown_item class="text-gray-700 data-focus:bg-green-100 data-focus:text-green-900 block px-4 py-2 text-sm">
<.dropdown_item
id="right-dropdown-item-0"
class="text-gray-700 data-focus:bg-green-100 data-focus:text-green-900 block px-4 py-2 text-sm"
>
Option X
</.dropdown_item>
<.dropdown_item class="text-gray-700 data-focus:bg-green-100 data-focus:text-green-900 block px-4 py-2 text-sm">
<.dropdown_item
id="right-dropdown-item-1"
class="text-gray-700 data-focus:bg-green-100 data-focus:text-green-900 block px-4 py-2 text-sm"
>
Option Y
</.dropdown_item>
</.dropdown_menu>
</.dropdown>

<!-- Bottom-end placement with larger offset -->
<.dropdown id="bottom-dropdown">
<.dropdown_trigger class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80">
<.dropdown_trigger
id="bottom-dropdown-trigger"
class="inline-flex justify-center rounded-lg bg-zinc-900 gap-x-1.5 px-3 py-2 text-sm font-semibold text-white hover:bg-zinc-700 active:text-white/80"
>
Bottom Menu
<svg class="-mr-1 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path
Expand All @@ -83,6 +106,7 @@
</svg>
</.dropdown_trigger>
<.dropdown_menu
id="bottom-dropdown-menu"
placement="bottom-end"
class="w-48 py-1 rounded-md bg-white shadow-xs ring-1 ring-gray-300 focus:outline-none"
transition_enter={
Expand All @@ -94,10 +118,16 @@
"transform opacity-0 scale-95"}
}
>
<.dropdown_item class="text-gray-700 data-focus:bg-purple-100 data-focus:text-purple-900 block px-4 py-2 text-sm">
<.dropdown_item
id="bottom-dropdown-item-0"
class="text-gray-700 data-focus:bg-purple-100 data-focus:text-purple-900 block px-4 py-2 text-sm"
>
Option 1
</.dropdown_item>
<.dropdown_item class="text-gray-700 data-focus:bg-purple-100 data-focus:text-purple-900 block px-4 py-2 text-sm">
<.dropdown_item
id="bottom-dropdown-item-1"
class="text-gray-700 data-focus:bg-purple-100 data-focus:text-purple-900 block px-4 py-2 text-sm"
>
Option 2
</.dropdown_item>
</.dropdown_menu>
Expand Down
Loading