WebAwesome Laminar LogoWebAwesome Laminar

Dropdown

Dropdowns expose additional content that "drops down" in a panel.

Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it.

Dropdowns are designed to work well with dropdown items to provide a list of options the user can select from. However, dropdowns can also be used in lower-level applications. The API gives you complete control over showing, hiding, and positioning the panel.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("View")  ))(  DropdownItem(    _.slots.icon(Icon(_.name := "scissors")())  )("Cut"),  DropdownItem(    _.slots.icon(Icon(_.name := "copy")())  )("Copy"),  DropdownItem(    _.slots.icon(Icon(_.name := "paste")())  )("Paste"),  Divider()(),  DropdownItem(    _.slots.submenu(DropdownItem(_.value := "show-all-images")("Show All Images")),    _.slots.submenu(DropdownItem(_.value := "show-thumbnails")("Show Thumbnails"))  )("Show images"),  Divider()(),  DropdownItem(    _.`type`.checkbox,    _.checked := true  )("Emoji Shortcuts"),  DropdownItem(    _.`type`.checkbox,    _.checked := true  )("Word Wrap"),  Divider()(),  DropdownItem(    _.variant.danger,    _.slots.icon(Icon(_.name := "trash")())  )("Delete"))

Examples

Getting the Selected Item

When an item is selected, the wa-select event will be emitted by the dropdown. You can inspect event.detail.item to get a reference to the selected item. If you've provided a value for each dropdown item, it will be available in event.detail.item.value.

Dropdown(  _.onSelect.map(_.detail.item.value.toOption) --> Observer[Option[String]](println),  _.slots.trigger(    Button(_.withCaret := true)("View")  ))(  DropdownItem(_.value := "full-screen")("Enter full screen"),  DropdownItem(_.value := "actual")("Actual size"),  DropdownItem(_.value := "zoom-in")("Zoom in"),  DropdownItem(_.value := "zoom-out")("Zoom out"))

To keep the dropdown open after selection, call event.preventDefault() in the wa-select event's callback.

Showing Icons

Use the icon slot to add icons to dropdown items. This works best with icon elements.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Edit")  ))(  DropdownItem(_.value := "cut", _.slots.icon(Icon(_.name := "scissors")()))("Cut"),  DropdownItem(_.value := "copy", _.slots.icon(Icon(_.name := "copy")()))("Copy"),  DropdownItem(_.value := "paste", _.slots.icon(Icon(_.name := "paste")()))("Paste"),  DropdownItem(_.value := "delete", _.slots.icon(Icon(_.name := "trash")()))("Delete"))

Showing Labels & Dividers

Use any heading, e.g. <h1>-<h6> to add labels and the <wa-divider> element for separators.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Device")  ))(  h3("Type"),  DropdownItem(_.value := "phone")("Phone"),  DropdownItem(_.value := "tablet")("Tablet"),  DropdownItem(_.value := "desktop")("Desktop"),  Divider()(),  DropdownItem(_.value := "more")("More options..."))

Showing Details

Use the details slot to display details, such as keyboard shortcuts, inside dropdown items.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Message")  ))(  DropdownItem(    _.value := "reply",    _.slots.details(span("⌘R"))  )("Reply"),  DropdownItem(    _.value := "forward",    _.slots.details(span("⌘F"))  )("Forward"),  DropdownItem(    _.value := "move",    _.slots.details(span("⌘M"))  )("Move"),  Divider()(),  DropdownItem(    _.value := "archive",    _.slots.details(span("⌘A"))  )("Archive"),  DropdownItem(    _.value := "delete",    _.slots.details(span("Del"))  )("Delete"))

Checkable Items

You can turn a dropdown item into a checkable option by setting type="checkbox". Add the checked attribute to make it checked initially. When clicked, the item's checked state will toggle and the dropdown will close. You can cancel the wa-select event if you want to keep it open instead.

Dropdown(  _.onSelect.map { event =>    event.detail.item.`type`.toOption match {      case Some("checkbox") =>        println(event.detail.item.value.toOption)        println(event.detail.item.checked.toOption)      case _ =>        println(event.detail.item.value.toOption)    }  } --> Observer.empty,  _.slots.trigger(    Button(_.withCaret := true)("View")  ))(  DropdownItem(_.`type`.checkbox, _.value := "canvas", _.checked := true)("Show canvas"),  DropdownItem(_.`type`.checkbox, _.value := "grid", _.checked := true)("Show grid"),  DropdownItem(_.`type`.checkbox, _.value := "source")("Show source"),  Divider()(),  DropdownItem(_.value := "preferences")("Preferences…"))

When a checkable option exists anywhere in the dropdown, all items will receive additional padding so they align properly.

Destructive Items

Add variant="danger" to any dropdown item to highlight that it's a dangerous action.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Project")  ))(  DropdownItem(    _.value := "share",    _.slots.icon(      Icon(_.name := "share")()    )  )("Share"),  DropdownItem(    _.value := "preferences",    _.slots.icon(      Icon(_.name := "gear")()    )  )("Preferences"),  Divider()(),  h3("Danger zone"),  DropdownItem(    _.value := "archive",    _.slots.icon(      Icon(_.name := "archive")()    )  )("Archive"),  DropdownItem(    _.value   := "delete",    _.variant := "danger",    _.slots.icon(      Icon(_.name := "trash")()    )  )("Delete"))

Placement

The preferred placement of the dropdown can be set with the placement attribute. Note that the actual position may vary to ensure the panel remains in the viewport.

Dropdown(  _.slots.trigger(    Button(      _.withCaret := true,      _.slots.end(        Icon(_.name := "chevron-right")()      )    )("File formats")  ))(  DropdownItem(_.value := "pdf")("PDF Document"),  DropdownItem(_.value := "docx")("Word Document"),  DropdownItem(_.value := "xlsx")("Excel Spreadsheet"),  DropdownItem(_.value := "pptx")("PowerPoint Presentation"),  DropdownItem(_.value := "txt")("Plain Text"),  DropdownItem(_.value := "json")("JSON File"))

Distance

The distance from the panel to the trigger can be customized using the distance attribute. This value is specified in pixels.

Dropdown(  _.distance := 30.0,  _.slots.trigger(    Button(_.withCaret := true)("Edit")  ))(  DropdownItem()("Cut"),  DropdownItem()("Copy"),  DropdownItem()("Paste"),  Divider()(),  DropdownItem()("Find"),  DropdownItem()("Replace"))

Offset

The offset of the panel along the trigger can be customized using the skidding attribute. This value is specified in pixels.

Dropdown(  _.skidding := 30.0,  _.slots.trigger(    Button(_.withCaret := true)("Edit")  ))(  DropdownItem()("Cut"),  DropdownItem()("Copy"),  DropdownItem()("Paste"),  Divider()(),  DropdownItem()("Find"),  DropdownItem()("Replace"))

To create submenus, nest dropdown items inside of a dropdown item and assign slot="submenu" to each one. You can also add dividers as needed.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Export")  ))(  DropdownItem(    _.slots.submenu(DropdownItem(_.value := "pdf")("PDF")),    _.slots.submenu(DropdownItem(_.value := "docx")("Word Document"))  )("Documents"),  DropdownItem(    _.slots.submenu(      DropdownItem(        _.slots.submenu(DropdownItem(_.value := "xlsx")("Excel (.xlsx)")),        _.slots.submenu(DropdownItem(_.value := "xls")("Excel 97-2003 (.xls)")),        _.slots.submenu(DropdownItem(_.value := "csv")("CSV (.csv)"))      )("Excel Formats")    ),    _.slots.submenu(      DropdownItem(        _.slots.submenu(DropdownItem(_.value := "ods")("OpenDocument (.ods)")),        _.slots.submenu(DropdownItem(_.value := "tsv")("Tab-separated (.tsv)")),        _.slots.submenu(DropdownItem(_.value := "json")("JSON (.json)"))      )("Other Formats")    ),    _.slots.submenu(DropdownItem(_.value := "numbers")("Apple Numbers"))  )("Spreadsheets"),  Divider()(),  DropdownItem(    _.slots.submenu(DropdownItem(_.`type`.checkbox, _.value := "compress")("Compress files")),    _.slots.submenu(      DropdownItem(_.`type`.checkbox, _.checked := true, _.value := "metadata")("Include metadata")    ),    _.slots.submenu(DropdownItem(_.`type`.checkbox, _.value := "password")("Password protect"))  )("Options"))

Dropdown items that have a submenu will not dispatch the wa-select event. However, items inside the submenu will, unless they also have a submenu.

As a UX best practice, avoid using more than one level of submenu when possible.

Disabling Items

Add the disabled attribute to any dropdown item to disable it.

Dropdown(  _.slots.trigger(    Button(_.withCaret := true)("Payment method")  ))(  DropdownItem(_.value := "cash")("Cash"),  DropdownItem(_.value := "check", _.disabled := true)("Personal check"),  DropdownItem(_.value := "credit")("Credit card"),  DropdownItem(_.value := "gift-card")("Gift card"))