Frontile

Dropdown

A menu activated by a button, representing a set of actions or displaying a list of options for user selection. Built on top of Popover and Listbox components with keyboard navigation support.

Import

import { Dropdown } from 'frontile';

Usage

Basic Dropdown

A feature-rich action menu showcasing icons, descriptions, shortcuts, dividers, and color intents.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';
import {
  ViewIcon,
  EditIcon,
  DuplicateIcon,
  ShareIcon,
  DownloadIcon,
  ArchiveIcon,
  DeleteIcon
} from 'site/components/icons';

export default class BasicDropdown extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action triggered:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @color='primary' @size='sm'>
        Project Actions
      </d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item|>
        <Item
          @key='view'
          @description='Open in read-only mode'
          @shortcut='mod+o'
        >
          <:start><ViewIcon /></:start>
          <:default>View Details</:default>
        </Item>
        <Item
          @key='edit'
          @description='Make changes to project'
          @shortcut='mod+e'
        >
          <:start><EditIcon /></:start>
          <:default>Edit Project</:default>
        </Item>
        <Item
          @key='duplicate'
          @description='Create a copy'
          @shortcut='mod+d'
          @withDivider={{true}}
        >
          <:start><DuplicateIcon /></:start>
          <:default>Duplicate</:default>
        </Item>
        <Item
          @key='share'
          @color='primary'
          @description='Invite team members'
          @shortcut='mod+shift+s'
        >
          <:start><ShareIcon /></:start>
          <:default>Share</:default>
        </Item>
        <Item @key='export' @color='success' @description='Download as file'>
          <:start><DownloadIcon /></:start>
          <:default>Export</:default>
        </Item>
        <Item
          @key='archive'
          @color='warning'
          @description='Move to archived projects'
          @withDivider={{true}}
        >
          <:start><ArchiveIcon /></:start>
          <:default>Archive Project</:default>
        </Item>
        <Item
          @key='delete'
          @color='danger'
          @description='Permanently delete'
          @class='text-danger'
          @shortcut='mod+backspace'
        >
          <:start><DeleteIcon /></:start>
          <:default>Delete Project</:default>
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

With Descriptions and Shortcuts

Add descriptions and keyboard shortcuts to menu items for better UX.

Note: The @shortcut argument is for display purposes only. You'll need to implement actual keyboard shortcut handling in your application using a library or custom implementation.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class DropdownWithDetails extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @color='primary' @size='sm'>Account</d.Trigger>

      <d.Menu @onAction={{this.onAction}} @color='primary' as |Item|>
        <Item @key='profile' @description='View and edit your profile'>
          My Profile
        </Item>
        <Item
          @key='settings'
          @description='Manage preferences'
          @shortcut='mod+,'
        >
          Settings
        </Item>
        <Item @key='billing' @description='View billing details'>
          Billing
        </Item>
        <Item
          @key='team'
          @description='Manage team members'
          @withDivider={{true}}
        >
          Team
        </Item>
        <Item @key='logout' @color='danger' @class='text-danger'>
          Log Out
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

With Selection

Enable single or multiple selection mode for choosing options.

Selected: bold
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class SelectableDropdown extends Component {
  @tracked selectedKeys = ['bold'];

  @action
  handleSelectionChange(keys: Set<string>) {
    this.selectedKeys = Array.from(keys);
    // eslint-disable-next-line
    console.log('Selected:', this.selectedKeys);
  }

  <template>
    <div class='demo-stack items-center'>
      <Dropdown @closeOnItemSelect={{false}} as |d|>
        <d.Trigger @size='sm'>Text Formatting</d.Trigger>

        <d.Menu
          @selectionMode='multiple'
          @selectedKeys={{this.selectedKeys}}
          @onSelectionChange={{this.handleSelectionChange}}
          as |Item|
        >
          <Item @key='bold'>Bold</Item>
          <Item @key='italic'>Italic</Item>
          <Item @key='underline'>Underline</Item>
          <Item @key='strikethrough'>Strikethrough</Item>
        </d.Menu>
      </Dropdown>

      <div class='text-sm text-neutral-soft'>
        Selected:
        {{this.selectedKeys}}
      </div>
    </div>
  </template>
}

Different Trigger Styles

Customize the trigger button appearance.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class TriggerStyles extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  <template>
    <div class='flex gap-2 flex-wrap'>
      <Dropdown as |d|>
        <d.Trigger @color='neutral' @size='sm'>Default</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>

      <Dropdown as |d|>
        <d.Trigger @color='primary' @size='sm'>Primary</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>

      <Dropdown as |d|>
        <d.Trigger @color='secondary' @size='sm'>Secondary</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>

      <Dropdown as |d|>
        <d.Trigger @color='success' @size='sm'>Success</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>

      <Dropdown as |d|>
        <d.Trigger @color='warning' @size='sm'>Warning</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>

      <Dropdown as |d|>
        <d.Trigger @color='danger' @size='sm'>Danger</d.Trigger>
        <d.Menu @onAction={{this.onAction}} as |Item|>
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
        </d.Menu>
      </Dropdown>
    </div>
  </template>
}

Control where the menu appears relative to the trigger.

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { fn } from '@ember/helper';
import { Dropdown, ButtonGroup } from 'frontile';

export default class MenuPositioning extends Component {
  @tracked placement = 'bottom-start';

  placements = [
    'top',
    'top-start',
    'top-end',
    'bottom',
    'bottom-start',
    'bottom-end',
    'left',
    'right'
  ];

  @action
  setPlacement(placement: string) {
    this.placement = placement;
  }

  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  isSelected = (p: string) => {
    return p === this.placement;
  };

  <template>
    <div class='demo-stack items-center'>
      <div class='flex gap-2 flex-wrap'>
        <ButtonGroup @size='xs' @color='primary' as |g|>
          {{#each this.placements as |p|}}
            <g.ToggleButton
              @isSelected={{this.isSelected p}}
              @onChange={{fn this.setPlacement p}}
            >
              {{p}}
            </g.ToggleButton>
          {{/each}}
        </ButtonGroup>
      </div>

      <div class='flex justify-center items-center h-32'>
        <Dropdown @placement={{this.placement}} as |d|>
          <d.Trigger @color='primary' @size='sm'>
            Menu ({{this.placement}})
          </d.Trigger>

          <d.Menu @onAction={{this.onAction}} as |Item|>
            <Item @key='option1'>Option 1</Item>
            <Item @key='option2'>Option 2</Item>
            <Item @key='option3'>Option 3</Item>
          </d.Menu>
        </Dropdown>
      </div>
    </div>
  </template>
}

Disabled Items

Disable specific menu items.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class DisabledItems extends Component {
  disabledKeys = ['share', 'delete'];

  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @color='primary' @size='sm'>File Actions</d.Trigger>

      <d.Menu
        @onAction={{this.onAction}}
        @disabledKeys={{this.disabledKeys}}
        as |Item|
      >
        <Item @key='open'>Open</Item>
        <Item @key='rename'>Rename</Item>
        <Item @key='share'>Share (Coming Soon)</Item>
        <Item @key='download'>Download</Item>
        <Item @key='delete' @color='danger' @class='text-danger'>
          Delete (Unavailable)
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

Keep Open on Select

Prevent the menu from closing when items are selected.

Active filters: recent
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class KeepOpenDropdown extends Component {
  @tracked filters = ['recent'];

  @action
  handleSelectionChange(keys: Set<string>) {
    this.filters = Array.from(keys);
    // eslint-disable-next-line
    console.log('Filters:', this.filters);
  }

  <template>
    <div class='demo-stack items-center'>
      <Dropdown @closeOnItemSelect={{false}} as |d|>
        <d.Trigger @size='sm'>Filter Options</d.Trigger>

        <d.Menu
          @selectionMode='multiple'
          @selectedKeys={{this.filters}}
          @onSelectionChange={{this.handleSelectionChange}}
          as |Item|
        >
          <Item @key='recent'>Recent</Item>
          <Item @key='starred'>Starred</Item>
          <Item @key='shared'>Shared with me</Item>
          <Item @key='archived'>Archived</Item>
        </d.Menu>
      </Dropdown>

      <div class='text-sm text-neutral-soft'>
        Active filters:
        {{this.filters}}
      </div>
    </div>
  </template>
}

With Dividers and Sections

Organize menu items into logical groups.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class SectionedDropdown extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @color='primary' @size='sm'>More Options</d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item|>
        <Item @key='new-file'>New File</Item>
        <Item @key='new-folder'>New Folder</Item>
        <Item @key='upload' @withDivider={{true}}>Upload</Item>
        <Item @key='copy'>Copy</Item>
        <Item @key='move'>Move</Item>
        <Item @key='rename' @withDivider={{true}}>Rename</Item>
        <Item @key='export'>Export</Item>
        <Item @key='share'>Share</Item>
        <Item @key='delete' @color='danger' @class='text-danger'>
          Delete
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

Custom Click Handlers

Use individual click handlers for specific items.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class CustomHandlers extends Component {
  @action
  handleEdit() {
    alert('Edit clicked');
  }

  @action
  handleDelete() {
    if (confirm('Are you sure you want to delete?')) {
      alert('Deleted!');
    }
  }

  @action
  handleDownload() {
    alert('Downloading...');
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @color='primary' @size='sm'>Actions</d.Trigger>

      <d.Menu as |Item|>
        <Item @key='view'>View Details</Item>
        <Item @key='edit' @onClick={{this.handleEdit}}>Edit</Item>
        <Item @key='download' @onClick={{this.handleDownload}}>
          Download
        </Item>
        <Item
          @key='delete'
          @color='danger'
          @class='text-danger'
          @onClick={{this.handleDelete}}
          @withDivider={{true}}
        >
          Delete
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

With Backdrop

Control the backdrop appearance behind the dropdown menu.

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { fn } from '@ember/helper';
import { Dropdown, ButtonGroup } from 'frontile';

export default class DropdownBackdrop extends Component {
  @tracked backdrop = 'none';

  @action
  setBackdrop(type: string) {
    this.backdrop = type;
  }

  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  isActiveBackdrop = (type: string) => {
    return this.backdrop === type;
  };

  <template>
    <div class='demo-stack items-center'>
      <ButtonGroup @size='xs' @color='primary' as |g|>
        <g.ToggleButton
          @isSelected={{this.isActiveBackdrop 'none'}}
          @onChange={{fn this.setBackdrop 'none'}}
        >
          No Backdrop
        </g.ToggleButton>
        <g.ToggleButton
          @isSelected={{this.isActiveBackdrop 'faded'}}
          @onChange={{fn this.setBackdrop 'faded'}}
        >
          Faded
        </g.ToggleButton>
        <g.ToggleButton
          @isSelected={{this.isActiveBackdrop 'blur'}}
          @onChange={{fn this.setBackdrop 'blur'}}
        >
          Blur
        </g.ToggleButton>
      </ButtonGroup>

      <Dropdown as |d|>
        <d.Trigger @color='primary' @size='sm'>
          Open Menu ({{this.backdrop}})
        </d.Trigger>

        <d.Menu
          @backdrop={{this.backdrop}}
          @onAction={{this.onAction}}
          as |Item|
        >
          <Item @key='option1'>Option 1</Item>
          <Item @key='option2'>Option 2</Item>
          <Item @key='option3'>Option 3</Item>
        </d.Menu>
      </Dropdown>
    </div>
  </template>
}

With Close Callback

Execute a callback when the dropdown closes.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class DropdownWithCallback extends Component {
  @action
  handleDidClose() {
    // eslint-disable-next-line
    console.log('Dropdown closed');
  }

  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action:', key);
  }

  <template>
    <Dropdown @didClose={{this.handleDidClose}} as |d|>
      <d.Trigger @color='primary' @size='sm'>Dropdown</d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item|>
        <Item @key='option1'>Option 1</Item>
        <Item @key='option2'>Option 2</Item>
        <Item @key='option3'>Option 3</Item>
      </d.Menu>
    </Dropdown>
  </template>
}

With Submenus

Group related actions behind a nested menu. Sub is a second, optional block param yielded by d.Menu alongside Item — existing as |Item| code keeps working unchanged, and you only reach for Sub where a nested menu is actually needed. Submenus open on hover, on click, or with , and close with or Esc.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class SubmenuDropdown extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action triggered:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @variant='outline' @size='sm'>Options</d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item Sub|>
        <Item @key='edit' @shortcut='mod+e'>Edit</Item>
        <Item @key='duplicate' @shortcut='mod+d' @withDivider={{true}}>
          Duplicate
        </Item>

        <Sub as |s|>
          <s.Trigger>More</s.Trigger>
          <s.Menu as |Item|>
            <Item @key='move-project'>Move to project…</Item>
            <Item @key='move-folder' @withDivider={{true}}>Move to folder…</Item>
            <Item @key='advanced'>Advanced options…</Item>
          </s.Menu>
        </Sub>

        <Item @key='share'>Share</Item>
        <Item @key='delete' @color='danger' @shortcut='mod+backspace'>
          Delete
        </Item>
      </d.Menu>
    </Dropdown>
  </template>
}

Nested Submenus

Submenus nest to any depth: a Sub's Menu yields Sub again.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class NestedSubmenuDropdown extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action triggered:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @variant='outline' @size='sm'>Share</d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item Sub|>
        <Item @key='copy-link'>Copy Link</Item>
        <Item @key='facebook'>Facebook</Item>

        <Sub as |s|>
          <s.Trigger>Other</s.Trigger>
          <s.Menu as |Item Sub|>
            <Item @key='whatsapp'>WhatsApp</Item>
            <Item @key='telegram'>Telegram</Item>

            <Sub as |s|>
              <s.Trigger>Email</s.Trigger>
              <s.Menu as |Item|>
                <Item @key='work-email'>Work email</Item>
                <Item @key='personal-email'>Personal email</Item>
              </s.Menu>
            </Sub>
          </s.Menu>
        </Sub>
      </d.Menu>
    </Dropdown>
  </template>
}

Sibling Submenus

Two submenu rows next to each other are mutually exclusive: moving from one onto the other closes the first as the second opens, so only one level is ever on screen.

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { Dropdown } from 'frontile';

export default class SiblingSubmenuDropdown extends Component {
  @action
  onAction(key: string) {
    // eslint-disable-next-line
    console.log('Action triggered:', key);
  }

  <template>
    <Dropdown as |d|>
      <d.Trigger @variant='outline' @size='sm'>Organize</d.Trigger>

      <d.Menu @onAction={{this.onAction}} as |Item Sub|>
        <Item @key='rename'>Rename</Item>
        <Item @key='duplicate' @withDivider={{true}}>Duplicate</Item>

        <Sub as |s|>
          <s.Trigger>Move to</s.Trigger>
          <s.Menu as |Item|>
            <Item @key='move-inbox'>Inbox</Item>
            <Item @key='move-archive'>Archive</Item>
            <Item @key='move-trash'>Trash</Item>
          </s.Menu>
        </Sub>

        <Sub as |s|>
          <s.Trigger>Share with</s.Trigger>
          <s.Menu as |Item|>
            <Item @key='share-team'>Team</Item>
            <Item @key='share-guests'>Guests</Item>
            <Item @key='share-link'>Anyone with the link</Item>
          </s.Menu>
        </Sub>
      </d.Menu>
    </Dropdown>
  </template>
}

Anatomy

Dropdown yields the pieces you assemble the menu from:

Yielded Purpose
d.Trigger Button that opens the menu
d.Menu The menu itself; yields an Item for each entry and, as a second block param, Sub for a nested menu
Item A single menu entry
Sub A nested menu, yielded alongside Item; yields its own s.Trigger and s.Menu

A Sub's s.Menu yields Item and Sub again, the same as the root d.Menu, so menus can nest to any depth.

The arguments declared once on the root d.Menu (@onAction, @selectionMode, @selectedKeys, @disabledKeys, @allowEmpty, @onSelectionChange, @variant, @intent, @shortcutVariant, @closeOnItemSelect, @disableTransitions, @transitionDuration) apply at every depth, so a nested s.Menu only needs its own items. Passing one of these same arguments to a nested s.Menu instead of the root has no effect — the root's value always wins, silently — so declare them once, on d.Menu.

s.Trigger needs no @keySub generates one, and a sub-trigger never fires @onAction. Sub positions its menu with @placement, @offsetOptions, @flipOptions, @shiftOptions, @middleware and @strategy, defaulting to @placement="right-start".

Accessibility

Dropdown is a Popover wrapping a Listbox with @type="menu", and inherits from both.

The trigger — a real <button>, so it is focusable and activates on Enter and Space — carries aria-haspopup="true", aria-controls pointing at the menu, and aria-expanded kept in sync. The menu itself is role="menu" and its items carry aria-labelledby, plus aria-disabled="true" for keys in @disabledKeys. Their role depends on whether the menu selects, as below.

Menu items never carry aria-selected — it is invalid on a menu item, which conveys state through aria-checked instead. When the menu selects, its rows take the matching checkable role and report their state: menuitemcheckbox with @selectionMode="multiple", menuitemradio with "single", each with aria-checked kept in sync. A menu that does not select keeps plain menuitem rows and no checked state, and a row that opens a submenu stays a plain menuitem whatever the level selects — activating it opens a menu rather than toggling a value.

Menu items share the Listbox's roving tabindex: exactly one item carries tabindex="0" — the active one, falling back to the first selected item and then to the first item that is not disabled — and every other item is -1.

Which keys are handled depends on where focus is:

Focus is on the trigger Behavior
Enter / Space Opens the menu, on key release
ArrowDown / ArrowUp Opens the menu
any letter Opens the menu (not with Cmd/Ctrl/Alt held)
Escape Closes
Tab Closes and moves on, without pulling focus back

Once open, focus moves into the menu and the list takes over:

Focus is in the menu Behavior
ArrowDown / ArrowUp Move the active item, within the open level
ArrowRight Opens the active row's submenu and moves to its first item
ArrowLeft Closes the current submenu and returns focus to its trigger; does nothing at the root level
Home / PageUp, End / PageDown First / last item, within the open level
Enter, Space Runs the active item's action, or opens its submenu
any single character Type-ahead to a matching item, scoped to the open level
Escape Closes the innermost open menu — at the root, focus returns to the trigger

Because the content is inside an Overlay with a focus trap, Tab from within the menu cycles inside it rather than leaving.

Opening the menu from the keyboard — Enter, Space, ArrowDown or ArrowUp on the trigger — activates its first row, per the WAI-ARIA menu button pattern, so the keyboard is immediately useful. Opening it with a pointer activates nothing, since moving the highlight somewhere the user never pointed is exactly what that pattern avoids. Pass an explicit @autoActivateMode to override either behaviour.

A submenu also opens on hovering its trigger, after a short delay, and stays open while the pointer travels toward it; moving onto a sibling row closes it. Only one submenu per level is ever open: opening one closes whichever sibling was open, so moving between two adjacent submenu rows swaps levels instead of stacking them. Opening a submenu by hover or click highlights nothing inside it — only opening it with the keyboard highlights its first row.

A submenu inherits its selection settings from the root menu, so @selectionMode, @selectedKeys, @disabledKeys, @allowEmpty, @onAction, @onSelectionChange and @closeOnItemSelect written once at the top apply at every depth. A submenu may also declare any of those seven itself, which wins for that level and the levels below it — so a navigation menu can hold a multi-select submenu without the root pretending to select. A submenu that declares nothing keeps inheriting.

Only those seven are a submenu's to override. Appearance and timing — @variant, @color, @shortcutVariant, @disableTransitions and @transitionDuration — stay the root's for the whole chain, so one menu cannot end up looking like two.

API

Dropdown

Element: HTMLUListElement

Arguments

Name Type Default Description
closeOnItemSelect boolean true Whether the dropdown should close upon selecting an item.
didClose function - Callback when closing has finished, including any exit transition.
flipOptions { padding?: Padding; mainAxis?: boolean; crossAxis?: boolean | 'alignment'; fallbackPlacements?: Placement[]; fallbackStrategy?: 'bestFit' | 'initialPlacement'; fallbackAxisSideDirection?: 'start' | ... 1 more ... | 'none'; ... 4 more ...; boundary?: Boundary; } - Options for the floating-ui flip middleware, which moves the content to the opposite side when it would overflow the viewport.
middleware Array - Additional floating-ui middleware, for positioning behavior beyond what placement, offsetOptions, flipOptions, and shiftOptions cover.
offsetOptions enum 5
placement enum 'bottom-start' Placement of the menu when open
shiftOptions { padding?: Padding; mainAxis?: boolean; crossAxis?: boolean; rootBoundary?: RootBoundary; elementContext?: ElementContext; altBoundary?: boolean; limiter?: { ...; }; boundary?: Boundary; } - Options for the floating-ui shift middleware, which nudges the content along its axis to keep it in view.
strategy enum 'absolute'

Blocks

Name Type Default Description
default * Array -
Released under MIT License - Created by Josemar Luedke