This is a Vue component, BpDropdown, for implementing dropdowns. It’s used in the navigation components in conjunctions with BpDirectional.

Usage

Props

  • delay (default: 0) – If hoverable, how long to delay before closing after the the mouse leaves the dropdown.
  • hoverable (default: false) – When set, the dropdown will open on hover, otherwise it will only open on click.
  • href (required) – The href for the link that’s overloaded to also open the dropdown.
  • id (required) – Required ID attribute value for accessibility purposes.
  • label (required) – Required next for the link.
  • labelClass (default: ‘’) – Allows adding additional classes to the link used to open the dropdown.
  • transition (default: ‘dropdown__transition’) – The name of a vue transition to use for the dropdown.

Slots

  • default – The default slot is used for the content within the dropdown.
  • link – Optional slot for providing more markup for the link than just ``.
  • button – Optional slot for overriding content of the button used to open the dropdown. The default value is an SVG chevron pointing downward.

Events

  • open – Emitted without a payload when the dropdown is opened.
  • close – Emitted without a payload when the dropdown is closed.
<!-- Default -->
<bp-dropdown label="Our Company" id="js-about">
    <nav class="dropdown__menu menu">
        <ul class="menu__list">
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit a</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Amet voluptas?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit exercitationem?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Dolor magni</span></a>
            </li>
        </ul>
    </nav>
</bp-dropdown>

<!-- Hover -->
<bp-dropdown-hoverable label="Our Company" id="js-about" :delay="250">
    <nav class="dropdown__menu menu">
        <ul class="menu__list">
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit a</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Amet voluptas?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit exercitationem?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Dolor magni</span></a>
            </li>
        </ul>
    </nav>
</bp-dropdown-hoverable>

<!-- Large -->
<bp-dropdown label="Our Company" id="js-about">
    <div class="container linkGroups">
        <input type="text">
        <div class="linkGroup">
            <div class="linkGroup__heading">Seacoast</div>
            <ul class="linkGroup__list -wide">
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Bar Harbor</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Camden</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Castine</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Damariscotta</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Kennebunkport</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Old Orchard Beach</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Portland</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Rockland</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Stonington</a></li>
            </ul>
        </div>
        <div class="linkGroup">
            <div class="linkGroup__heading">Parks</div>
            <ul class="linkGroup__list">
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Acadia</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Baxter</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Camden Hills</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Popham Beach</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Quoddy Head</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Reid</a></li>
            </ul>
        </div>
        <div class="linkGroup">
            <div class="linkGroup__heading">Activities</div>
            <ul class="linkGroup__list">
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Agricultural Attractions</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Arts &amp; Culture</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Camping</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Fishing</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Guide Services</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Hiking &amp; Climbing</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Hunting</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Lighthouses &amp; Sightseeing</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Shopping</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Spas, Health &amp; Wellness</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Wildlife Watching</a></li>
                <li class="linkGroup__item"><a class="linkGroup__link" href="#">Winter Activities</a></li>
            </ul>
        </div>
    </div>
</bp-dropdown>

<!-- Link -->
<bp-dropdown-link href="/about" label="Our Company" id="js-about">
    <nav class="dropdown__menu menu">
        <ul class="menu__list">
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit a</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Amet voluptas?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Sit exercitationem?</span></a>
            </li>
            <li class="menu__item">
                <a class="menu__link" href=""><span>Dolor magni</span></a>
            </li>
        </ul>
    </nav>
</bp-dropdown-link>

  • Content:
    <template>
        <div
            class="dropdown"
            :class="{'-open': isOpen}"
        >
            <button
                ref="button"
                :aria-controls="id"
                :aria-expanded="String(isOpen)"
                class="dropdown__button"
                :class="labelClass"
                @click.prevent="toggle"
            >
                <slot name="button">
                    {{ label }}
                    <svg
                        class="dropdown__icon"
                        viewBox="0 0 24 24"
                        stroke-width="1"
                        stroke="currentColor"
                        fill="none"
                    ><polyline points="6 9 12 15 18 9" /></svg>
                </slot>
            </button>
            <div
                v-show="isOpen"
                :id="id"
                ref="dropdown"
                class="dropdown__content"
            >
                <slot />
            </div>
        </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import useOpenable from '@resources/js/components/UseOpenable.vue'
    
    const dropdown = ref(null)
    const button = ref(null)
    
    defineProps({
        id: { type: String, required: true },
        label: { type: String, required: true },
        labelClass: { type: String, default: '' },
        transition: { type: String, default: 'dropdown__transition' },
    })
    
    const { isOpen, toggle } = useOpenable(dropdown, button)
    
    </script>
    
  • URL: /components/raw/dropdown/BpDropdown.vue
  • Filesystem Path: resources/styles/atoms/dropdown/BpDropdown.vue
  • Size: 1.3 KB
  • Content:
    <template>
        <div
            class="dropdown"
            :class="{'-open': isOpen}"
            @mouseleave="delayClose(delay)"
            @mouseenter="keepOpen"
        >
            <button
                ref="button"
                :aria-controls="id"
                :aria-expanded="String(isOpen)"
                class="dropdown__button"
                :class="labelClass"
                @click.prevent="toggle"
                @mouseenter="open"
            >
                <slot name="button">
                    {{ label }}
                    <svg
                        class="dropdown__icon"
                        viewBox="0 0 24 24"
                        stroke-width="1"
                        stroke="currentColor"
                        fill="none"
                    ><polyline points="6 9 12 15 18 9" /></svg>
                </slot>
            </button>
            <div
                v-show="isOpen"
                :id="id"
                ref="dropdown"
                class="dropdown__content"
            >
                <slot />
            </div>
        </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import useOpenable from '@resources/js/components/UseOpenable.vue'
    
    const dropdown = ref(null)
    const button = ref(null)
    
    defineProps({
        delay: { type: Number, default: 0 },
        id: { type: String, required: true },
        label: { type: String, required: true },
        labelClass: { type: String, default: '' },
        transition: { type: String, default: 'dropdown__transition' },
    })
    
    const { isOpen, open, keepOpen, delayClose, toggle } = useOpenable(dropdown, button)
    
    </script>
    
  • URL: /components/raw/dropdown/BpDropdownHoverable.vue
  • Filesystem Path: resources/styles/atoms/dropdown/BpDropdownHoverable.vue
  • Size: 1.5 KB
  • Content:
    <template>
        <div
            ref="dropdown"
            class="dropdown"
            :class="{'-open': isOpen}"
        >
            <a
                ref="link"
                :aria-controls="id"
                :aria-expanded="String(isOpen)"
                class="dropdown__link"
                :class="labelClass"
                :href="href"
                @click.prevent="toggle"
            >
                <slot name="link">
                    {{ label }}
                    <svg
                        class="dropdown__icon"
                        viewBox="0 0 24 24"
                        stroke-width="1"
                        stroke="currentColor"
                        fill="none"
                    ><polyline points="6 9 12 15 18 9" /></svg>
                </slot>
            </a>
            <div
                v-show="isOpen"
                :id="id"
                ref="dropdown"
                class="dropdown__content"
            >
                <slot />
            </div>
        </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import useOpenable from '@resources/js/components/UseOpenable.vue'
    
    const dropdown = ref(null)
    const link = ref(null)
    
    defineProps({
        delay: { type: Number, default: 0 },
        hoverable: { type: Boolean, default: false },
        href: { type: String, required: true },
        id: { type: String, required: true },
        label: { type: String, required: true },
        labelClass: { type: String, default: '' },
        transition: { type: String, default: 'dropdown__transition' },
    })
    
    const { toggle, isOpen } = useOpenable(dropdown, link)
    
    </script>
    
  • URL: /components/raw/dropdown/BpDropdownLink.vue
  • Filesystem Path: resources/styles/atoms/dropdown/BpDropdownLink.vue
  • Size: 1.5 KB
  • Content:
    @use "/resources/styles/common" as *;
    @use "/resources/styles/config";
    
    .dropdown {
        $b: &;
    
        --dropdown-color: var(--color, #{config.$white});
        --dropdown-color-contrast: var(--color-contrast, #{config.$plain-text});
    
        position: relative;
    
        &__button,
        &__link {
            color: config.$link;
            display: inline-block;
            padding: config.$thin-padding;
            z-index: 2;
        }
    
        &__icon {
            height: 1em;
            vertical-align: middle;
            width: 1em;
        }
    
        &__content {
            --color: var(--dropdown-color-contrast);
            --color-hover: #{config.$secondary};
            background-color: var(--dropdown-color);
            box-shadow: config.$low-shadow;
            color: var(--dropdown-color-contrast);
            position: absolute;
            z-index: 1;
        }
    
        &.-rightEdge {
            #{$b}__content {
                left: auto;
                right: 0;
            }
        }
    
        &.-fullWidth {
            position: static;
    
            #{$b}__content {
                left: 0;
                right: 0;
            }
        }
    
        &__transition {
            &-enter-active {
                transform-origin: top;
                transition: opacity var(--duration-moderate), transform var(--duration-moderate);
                transform: rotateX(0);
            }
            &-enter,
            &-leave-to {
                opacity: 0;
                transform: rotateX(90deg);
            }
        }
    }
    
  • URL: /components/raw/dropdown/_index.scss
  • Filesystem Path: resources/styles/atoms/dropdown/_index.scss
  • Size: 1.4 KB