Skip to main content

Shoelace Protips

General tips for using Shoelace components

Conditional attributes

When setting an attribute flag, some flags need an actual value like “true” or “false”, but some — like checked within sl-menu-item — just need to be present. In that case, setting checked=“false” will still evaluate as true because the mere presence of the attribute is truthy. An empty string, eg checked="" , will also evaluate as true, so you don’t want to interpolate your conditional inside of quotes like checked="#{some conditional}".

For these attributes, you should instead evaluate the value in inline Ruby code so that, if it’s false, the attribute isn’t attached to the dom at all:

sl-checkbox[
  checked = (@variable == value)
]

This will render as <sl-checkbox checked></sl-checkbox> if true and simply <sl-checkbox></sl-checkbox> if false.


Nested rendering

Shoelace rendering is more flexible than it looks: in many cases, the child of a Shoelace wrapper component such as sl-menu or sl-button-group doesn’t actually have to be a Shoelace component. And if the child is a Shoelace element, it doesn’t have to be the direct descendant of the wrapper. For example, within an sl-dropdown, which composes an sl-menu as the popover, you can nest the sl-menu-item components inside of Rails helpers like link_to:

sl-menu
  = link_to user_info_path
    sl-menu-item
      sl-icon name="cog-8-tooth" slot="prefix"
      | Profile settings
  = link_to destroy_user_session_path
    sl-menu-item
      sl-icon name="arrow-right-on-rectangle" slot="prefix"
      | Sign out

Likewise, you can use a Rails ViewComponent that wraps an sl-button within an sl-button-group, and it will still render the group correctly:

sl-button-group
  sl-button variant="primary"
    | Shoelace button
  = render SharedUI::ButtonToComponent.new(\
    text: "Second button inside a VC",
    path: complete_path,
    options: {\
      "data-test-id" => "test-button",
    })
  sl-button
    | Another button