The loco_icon helper renders an inline SVG from any installed icon library. LocoMotion bundles only a small, curated set of Heroicons — just enough that the built-in components (modal close, calendar chevrons, the standard alert icons, and friends) work with zero setup. See the Loco::IconComponent API docs for the full list of bundled icons.

Every other icon — including the rest of Heroicons and libraries like Lucide, Phosphor, Tabler, and more — is synced into your own application once (see the examples below).

Upgrading from hero_icon?

Earlier versions of LocoMotion rendered icons with hero_icon and Hero::IconComponent. The Migrating to the Icon Engine guide walks through every change step by step.

Basic Icons

By default, icons are displayed with the size-5 Tailwind class to set the width and height. This can be overridden without using the ! Tailwind modifier because we utilize the :where() pseudo-class to ensure that our default classes have the lowest CSS specificity possible.

The icon color inherits the text color of the parent element.

You can pass the icon as the first positional argument or via the icon: keyword argument.

Preview
Code
= loco_icon("academic-cap")
= loco_icon(icon: "adjustments-horizontal")
%span.text-blue-500
  = loco_icon("archive-box")

Variants

Heroicons ships four variants. Append the variant to the icon token — name/variant (outline is the default); other libraries expose their own variants / weights the same way (e.g. phosphor:heart/duotone).

Preview
Code
= loco_icon("bolt/outline", css: "size-8")
= loco_icon("bolt/solid", css: "size-8")
= loco_icon("bolt/mini", css: "size-5")
= loco_icon("bolt/micro", css: "size-4")

Customized Icons

You can customize the size, color, and other properties of the icons using standard Tailwind classes.

Preview
Code
= loco_icon("no-symbol", css: "size-4 text-red-600")
= loco_icon("arrow-trending-up", css: "size-10 text-green-600")
= loco_icon("exclamation-triangle", css: "size-14 text-yellow-400 animate-pulse")

Other Libraries

To use a library beyond the curated bundled set, sync it into your app once and name it in the icon token as library:name:

bin/rails loco_motion:icons:add lucide phosphor
= loco_icon("lucide:heart")
= loco_icon("phosphor:heart/duotone")

The renderer checks your app's app/assets/svg/icons first, then falls back to the bundled icons — so synced libraries just work.

Duotone icons have two independently colorable layers: the outline strokes with currentColor, so text-* classes color it, while the tint layer inherits the SVG fill, so fill-* classes color it.

Prefer a different library by default? Set it once in an initializer (and pick a matching variant, or nil for a flat library):

# config/initializers/loco_motion.rb
LocoMotion.configure do |config|
  config.default_icon_library = :lucide
  config.default_icon_variant = :outline
end
Preview
Code
= loco_icon("lucide:heart", css: "size-8 text-red-500")
= loco_icon("phosphor:heart/duotone", css: "size-8 text-purple-500 fill-pink-500")
Made with by Profoundry .
Copyright © 2023-2026 Profoundry LLC.
All rights reserved.