rails-active-ui
A Fomantic-UI component system for Rails. Views use .html.ruby files with PascalCase component calls.
Setup
Add to your Gemfile:
gem "rails-active-ui"
Engine initializers
The gem's engine (Ui::Engine) registers the following automatically:
Autoload paths -- app/lib and app/blocks are added to the autoload paths so Component and block classes are available everywhere.
Asset paths -- formantic-ui/ (Fomantic-UI CSS/JS distribution) and app/javascript/ (Stimulus controllers) are added to Propshaft's asset paths. Reference them in your layout:
# CSS
StylesheetLink("stylesheets.css") # Fomantic-UI stylesheet
# jQuery + Fomantic-UI component JS (must come before importmap)
text
# Importmap (loads Stimulus controllers)
JavascriptImportmap()
Importmap -- the gem's config/importmap.rb is prepended to the app's importmap. It pins:
ui-- the main entry point (ui/index.js)ui/controllers/*-- all Fomantic-UI Stimulus bridge controllersemoji-picker-element-- emoji picker from CDN
Helpers -- ComponentHelper and FuiHelper are included into ActionView::Base automatically.
Stimulus controllers
Register the Fomantic-UI Stimulus controllers in your app's app/javascript/controllers/index.js:
import { Application } from "@hotwired/stimulus"
import { registerFuiControllers } from "ui"
const application = Application.start()
registerFuiControllers(application)
These are thin jQuery bridge controllers that initialize Fomantic-UI widgets in connect() and tear them down in disconnect(), making them Turbo-compatible.
Rails engine usage
If you're using rails-active-ui inside a Rails engine, your engine needs to register the gem's assets manually since engines don't inherit the host app's asset paths:
# lib/my_engine/engine.rb
class Engine < ::Rails::Engine
initializer "my_engine.assets" do |app|
ui_gem = Gem::Specification.find_by_name("rails-active-ui")
app.config.assets.paths << File.join(ui_gem.gem_dir, "app/assets")
end
end
Form Builder
rails-active-ui ships with FomanticFormBuilder, a drop-in ActionView::Helpers::FormBuilder subclass that wraps every field helper in Fomantic-UI markup.
Set it as the default in your ApplicationController:
class ApplicationController < ActionController::Base
ActionView::Base.default_form_builder = FomanticFormBuilder
end
Inside a Form() block, method_missing delegates to the form builder. Standard Rails form helpers become PascalCase calls:
Form(url: users_path, method: :post) {
TextField(:name, required: true)
EmailField(:email)
Select(:role, [["Admin", "admin"], ["User", "user"]], dropdown: true)
CheckBox(:terms, label: "I agree to the Terms")
HiddenField(:token)
Submit("Save", color: "green")
}
Available form helpers
.html.ruby call |
Form builder method | Description |
|---|---|---|
TextField(:name) |
f.text_field :name |
Text input wrapped in .field |
EmailField(:email) |
f.email_field :email |
Email input |
PasswordField(:password) |
f.password_field :password |
Password input |
NumberField(:age) |
f.number_field :age |
Number input |
TextArea(:bio) |
f.text_area :bio |
Textarea |
Select(:role, choices) |
f.select :role, choices |
Select dropdown |
CheckBox(:terms) |
f.check_box :terms |
Checkbox with Fomantic styling |
RadioButton(:plan, "pro") |
f.radio_button :plan, "pro" |
Radio button |
HiddenField(:token) |
f.hidden_field :token |
Hidden input (no wrapper) |
FileField(:avatar) |
f.file_field :avatar |
File upload |
Submit("Save") |
f.submit "Save" |
Submit button with Fomantic styling |
Field options
All field helpers accept these options:
label:-- override label text (nilto suppress)required:-- adds "required" class and asteriskdisabled:-- adds "disabled" classinline:-- label sits beside the inputwidth:-- Fomantic grid column word (e.g."six","three")error:-- error message stringhint:-- grey note beneath the inputfield_class:-- extra classes on the wrapping.fielddivinput_class:-- extra classes on the input element
Submit button options
color:-- Fomantic color (e.g."green","red","blue")size:-- Fomantic size (e.g."tiny","large")basic:-- basic button styleicon:-- icon name (e.g."checkmark")
Field groups
Form(url: users_path) {
FieldsGroup(equal_width: true) {
TextField(:first_name)
TextField(:last_name)
}
}
Form-level messages
Form(url: users_path) {
ErrorMessage("Something went wrong", ["Email is taken"])
SuccessMessage("All done!", "Profile updated.")
WarningMessage("Heads up", ["Verify your email"])
}