ActiveAdmin is still one of the fastest ways to get an internal admin panel in front of a Rails app. Its default look, though, hasn’t really changed in years — a top bar, unstyled confirm dialogs, Formtastic forms that look exactly like every ActiveAdmin app built since 2012. Prism exists to fix that without touching ActiveAdmin’s internals, a Sass compiler, or a JS bundler.
Install, with nothing else required
# Gemfilegem "active_admin_prism"bundle installrails g active_admin_prism:installThat generator makes exactly two idempotent changes: it appends ActiveAdminPrism.enable! to config/initializers/active_admin.rb, and — only if the file exists — it injects one @import line into active_admin.scss right before ActiveAdmin’s own mixins import. Both CSS and JS ship precompiled and pre-minified inside the gem, so there’s no Sass compiler step and no JS bundler step to wire up, on either Sprockets or Propshaft.
Tip
Verifying the install takes four checks: sign in and see a left sidebar instead of a top bar,
confirm active_admin.css loads before active_admin_prism/prism.css (order matters), and click
any Delete icon — it should open a styled confirm dialog, not the browser’s native confirm()
popup.
The “light touch” philosophy, and why it’s not just marketing language
The core design constraint behind Prism is that it should survive ActiveAdmin version upgrades without needing to be re-patched. That rules out forking ActiveAdmin’s view classes or monkey-patching its internals. Instead:
- The sidebar replaces ActiveAdmin’s
headerslot throughActiveAdmin::ViewFactory.register— a mechanism ActiveAdmin itself documents and supports. Existingmenu do |m| ... endblocks (nested groups,priority:, conditionalif:) render completely unchanged; only the drawing differs. - Panels, tables, and Formtastic form inputs are reskinned with pure CSS against markup that already exists (
.panel,.index_table,li.input.*) — no Ruby view overrides at all. - Confirm dialogs are rerouted through ActiveAdmin’s own jQuery UI dialog by overriding
$.rails.allowAction, which is jquery-ujs’s own documented extension point, not a private API. - Color overrides go through Sass variables marked
!defaultin ActiveAdmin’s own stylesheets — Prism ships avariable_overrides.scssthat’s auto-wired before ActiveAdmin’s mixins import, so a host app can override further just by setting a variable before that import.
The result: upgrading ActiveAdmin and upgrading Prism are expected to be independent operations.
What you actually get
A collapsible sidebar with nested navigation, icons, and priority ordering:
menu label: "Orders", parent: "E-Commerce", priority: 2, html_options: { icon: :box }parent: accepts an array for deeper nesting (parent: ["Analytics", "Reports"]), and a hamburger toggle collapses the whole sidebar down to an icon-only rail on desktop, persisted via localStorage. Items with no explicit icon get a deterministic auto-assigned one from a generic set, based on a hash of the label — enough to keep the collapsed rail from looking broken, controllable via config.auto_nav_icons.
Toggle switches, as a drop-in Formtastic input type:
form do |f| f.input :active, as: :prism_toggleendVendored Select2, with no separate gem or npm dependency, auto-enhancing every <select> when config.select2 = true — the one flag in the whole gem that defaults to off, specifically because it’s the one feature most likely to need design review before a team wants it.
Consolidated action items. When a title bar would otherwise collect more than three action buttons (config.action_items_dropdown_threshold), they collapse into a single Select2 “jump menu” instead of visually competing with each other.
A reskinned sign-in page — Prism ships its own copies of all six Devise auth view templates (sessions, registrations, passwords, confirmations, unlocks), configurable with your own logo and copy:
ActiveAdminPrism.configure do |config| config.login_logo = -> { image_tag "my_logo.svg", height: 40 } config.login_app_name = "My Company Admin" config.login_tagline = "Internal operations console"endConfiguration is one block, and it’s honest about what’s static vs. dynamic
ActiveAdminPrism.configure do |config| config.sidebar = true config.colorize_action_icons = true config.styled_confirms = true config.collapsible_filters = true config.active_filters_bar = true config.flash_dismissible = true config.flash_auto_dismiss = true config.flash_auto_dismiss_seconds = 5 config.menu_search = true config.select2 = false config.sidebar_collapsible = true config.action_items_dropdown_threshold = 3endActiveAdminPrism.enable!Server-side flags like sidebar and login_* are plain Ruby render-time decisions. Client-side flags — styled_confirms, collapsible_filters, the flash settings — are read by JS/CSS through body classes and data attributes rendered fresh on every request, which means they’re safe to flip through a feature-flag system without a server restart.
Note
Turning Prism off doesn’t require uninstalling it. Flip every flag to false for a mostly-default
experience (the unconditional CSS reskin of panels/forms stays), or fully revert by commenting out
the enable! call and the @import line — no code to unwind either way.
Prism is MIT-licensed, requires ActiveAdmin 3.x and Rails 7+, and has a live demo running on Render if you want to see the sidebar and forms before adding it to a Gemfile — sign in with admin@example.com / password (free-tier hosting, so the first load can be slow to wake up).
For the full README, integration guide, configuration reference, and changelog, see the detailed Prism documentation.