Skip to main content

Shoelace Protips

Recipes Protips

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