Skip to content

SDropdown ​

Обзор ​

Выпадающая панель (floating overlay) с позиционированием относительно якоря.

Usage ​

Открытие по клику на trigger-слот.

API ​

Краткий справочник props, slots и events — см. API Reference.

Guide ​

SDropdown позиционирует floating-панель относительно якоря из слота #trigger или внешнего reference.

  • Управление открытием — через v-model (boolean).
  • Слот #trigger получает toggle, open, triggerProps для a11y-связки с панелью.
  • Trigger может быть любым интерактивным элементом — кнопка, иконка, chip; компонент не привязан к SButton.
  • Для hover-режима включите showOnHover — панель открывается по наведению на trigger и content.
  • Общие паттерны overlay — см. Overlays.

Фокус и клавиатура ​

Панель телепортирована в конец body, поэтому браузерный Tab до неё не доходит — фокусом управляет сам SDropdown (WAI-ARIA menu button и немодальный dialog):

  • Открытие с якоря переносит фокус в панель. С клавиатуры — на первый пункт меню, иначе на первый интерактивный элемент, а если его нет — на саму панель; мышью — на саму панель (без кольца фокуса, но стрелки, Escape и Tab уже работают). Якорь-поле ввода (input, combobox) и открытие наведением фокус не уводят; focusOnOpen: false отдаёт фокус потребителю (так делает SSelect).
  • Закрытие, пока фокус в панели (Escape, выбор пункта, клик снаружи по пустому месту), возвращает фокус на элемент, с которого панель открыли, — обычно на якорь.
  • ↑ ↓ Home End переходят между пунктами: строками SListItem вне SList и элементами с ролью menuitem*.
  • Tab с последнего элемента панели закрывает её и продолжает обход от якоря, Shift+Tab с первого — закрывает и встаёт на якорь: панель ведёт себя так, будто стоит в DOM сразу за якорем.
  • Панель — role="dialog" с именем якоря (aria-labelledby на triggerProps.id, без него — aria-label якоря) или явным panelLabel.

Меню — проп menu: панель role="menu", строки SListItem в ней получают роль menuitem, якорь — aria-haspopup="menu"; ↓/↑ на якоре открывают меню на первом/последнем пункте, Tab закрывает меню и уходит дальше.

vue
<SDropdown v-model="isOpen" menu>
  <template #trigger="{ toggle, triggerProps }">
    <SButton v-bind="triggerProps" @click="toggle">Действия</SButton>
  </template>
  <template #content>
    <SDropdownMenu :width="220">
      <SListItem title="Переименовать" @click="rename" />
      <SListItem title="Удалить" @click="remove" />
    </SDropdownMenu>
  </template>
</SDropdown>

Bottom sheet на мобильных ​

На viewport уже sheetBreakpoint (по умолчанию 768) содержимое показывается не floating-панелью у якоря, а bottom sheet — это поведение по умолчанию. Отключается пропом sheet: false для случаев, где панель должна оставаться привязанной к якорю.

Слот #content не меняется — он получает isSheet, чтобы содержимое могло адаптироваться, и close. Заголовок шапки задаётся через sheetTitle, дополнительные элементы — слотами #sheet-header-left / #sheet-header-right.

Закрытие: свайп вниз по шапке, клик по затемнению (dismissOnClickOutside), Escape (dismissOnEscape). Пока sheet открыт, скролл страницы заблокирован, фокус переходит на панель и возвращается на trigger при закрытии. В режиме sheet showOnHover не действует.

Размеры настраиваются CSS-переменными на .s-ui-dropdown-sheet: --s-ui-dropdown-sheet-max-height (по умолчанию 80svh) и --s-ui-dropdown-sheet-overdrag.

vue
<SDropdown v-model="isOpen" sheet-title="Выберите действие">
  <template #trigger="{ toggle, triggerProps }">
    <button type="button" v-bind="triggerProps" @click="toggle">Menu</button>
  </template>
  <template #content="{ isSheet, close }">…</template>
</SDropdown>
vue
<SDropdown v-model="isOpen">
  <template #trigger="{ toggle, triggerProps }">
    <button type="button" v-bind="triggerProps" @click="toggle">Menu</button>
  </template>
  <template #content>…</template>
</SDropdown>

Вложенные dropdown ​

SDropdown внутри слота #content другого SDropdown связывается с ним автоматически. Панели телепортируются в body, но родитель знает о вложенных и не считает их «снаружи». Связь строится по дереву компонентов: вложенный SDropdown должен быть потомком родителя во Vue-дереве, положение его панели в DOM не важно.

  • Клик и наведение внутри вложенной панели не закрывают родителя, в том числе при showOnHover.
  • Клик по панели родителя вне вложенной закрывает только вложенную.
  • Escape закрывает самую глубокую открытую панель, следующий Escape — её родителя.
  • Родитель с showOnHover остаётся открытым, пока открыта вложенная панель.

Trigger подменю удобно делать из SListItem; для подменю по наведению включите showOnHover и placement: right-start, а block растянет обёртку trigger на ширину строки.

vue
<SDropdown v-model="isMenuOpen">
  <template #trigger="{ toggle, triggerProps }">
    <SButton v-bind="triggerProps" @click="toggle">Действия</SButton>
  </template>
  <template #content>
    <SDropdownMenu :width="220">
      <SListItem title="Переименовать" />
      <SDropdown
        v-model="isMoveOpen"
        :placement="ESDropdownPlacement.RIGHT_START"
        show-on-hover
        block
      >
        <template #trigger="{ triggerProps }">
          <SListItem v-bind="triggerProps" title="Переместить в…" />
        </template>
        <template #content>…</template>
      </SDropdown>
    </SDropdownMenu>
  </template>
</SDropdown>

Props ​

Со стрелкой ​

Placement top ​

Match reference width ​

Show on hover ​

Меню с клавиатуры: Enter, Space или ↓ открывают его на первом пункте, ↑/↓, Home и End — по пунктам, Escape возвращает фокус на кнопку, Tab закрывает меню и идёт дальше.

Fit viewport ​

Панель не помещается ни снизу, ни сверху: открывается там, где места больше, и ограничивается по высоте с прокруткой вместо выхода за край.

Bottom sheet ​

Содержимое как bottom sheet: закрытие свайпом вниз по шапке, кликом по затемнению или Escape.

Examples ​

Вложенные dropdown ​

Подменю по наведению и по клику внутри панели: родитель открыт, пока используется вложенная панель, Escape закрывает только самую глубокую.

API Reference ​

Свойства ​

ИмяТипОписаниеПо умолчанию
placementESDropdownPlacementПредпочтительное положение панели относительно якоря.'bottom-start'
offsetnumberОтступ панели от якоря в пикселях.8
flipbooleanПереворот панели при нехватке места; если не помещается ни одна сторона, берётся та, где места больше.true
shiftbooleanСдвиг панели вдоль оси, чтобы оставаться в viewport (по умолчанию включён: иначе панель у края уходит за него).true
matchReferenceWidthbooleanШирина панели равна ширине якоря.false
fitViewportbooleanОграничение высоты панели свободным местом с выбранной стороны: панель прокручивается, а не уходит за край.false
surfaceClassstringДополнительный CSS-класс поверхности панели.—
teleportTostring | falseСелектор контейнера для Teleport; false — без телепорта.'body'
dismissOnClickOutsidebooleanЗакрытие по клику вне панели и якоря; вложенные панели считаются внутри.true
dismissOnEscapebooleanЗакрытие по Escape; при открытой вложенной панели закрывается только она.true
disabledbooleanБлокирует открытие и взаимодействие.false
referenceHTMLElement | nullDOM-элемент якоря; если не задан, используется слот trigger.null
contentIdstringid панели для aria-controls.—
viewportPaddingnumberВнутренний отступ от краёв viewport при позиционировании.8
boundaryESDropdownBoundaryГраницы позиционирования и готовности панели: clipping-ancestors — пересечение viewport с overflow-предками якоря, viewport — только viewport (панель может выходить за скролл-контейнер якоря; скрытие при уходе якоря из его клип-границ сохраняется).'clipping-ancestors'
blockbooleanРастягивает обёртку триггера на всю ширину контейнера.false
arrowbooleanПоказывает стрелку-указатель к якорю.false
showOnHoverbooleanОткрывает и закрывает панель по наведению на якорь и содержимое.false
hoverLeaveDelaynumberЗадержка перед закрытием при уходе курсора с якоря или панели, мс.100
sheetbooleanBottom sheet вместо floating-панели на мобильном viewport.true
sheetBreakpointnumberШирина viewport в px, ниже которой включается bottom sheet.S_DROPDOWN_SHEET_BREAKPOINT
sheetTitlestringЗаголовок шапки bottom sheet.''
menubooleanПанель — меню (WAI-ARIA menu button): role="menu", строки SListItem в ней — menuitem, ↓/↑ на якоре открывают меню на первом/последнем пункте, Tab закрывает меню и идёт дальше. Без него панель — немодальный dialog, названный своим якорем.false
focusOnOpenbooleanПереносить фокус в панель при открытии с якоря: с клавиатуры — на первый пункт меню, иначе на первый интерактивный элемент или на саму панель; мышью — на саму панель. Якорь-поле ввода (combobox, input) фокус держит всегда; false — фокусом панели управляет потребитель.true
panelLabelstringДоступное имя панели; по умолчанию панель называется якорем (aria-labelledby).—
modelValue / v-modelbooleanДвустороннее значение компонента (v-model).false

Слоты ​

ИмяОписание
triggerЯкорь открытия: open, toggle, close, isSheet, triggerProps для a11y
sheet-header-leftОбласть шапки bottom sheet слева от заголовка
sheet-header-rightОбласть шапки bottom sheet справа от заголовка
contentСодержимое панели; resolvedPlacement — итоговая позиция, isSheet — режим bottom sheet