This gem provides a set of ready-to-use Phlex components for common Bulma components and elements, making it easy to build beautiful, responsive interfaces with a clean, Ruby-focused API.
Add this line to your application's Gemfile:
gem "bulma-phlex"And then execute:
bundle installOr install it yourself as:
gem install bulma-phlexThis gem requires:
- Ruby 3.2.10 or higher
- Phlex 2.4.1 or higher
- Bulma CSS (which you'll need to include in your application)
-
Include Bulma CSS in your application. You can add it via npm/yarn, CDN, or the bulma-rails gem.
-
Require the gem in your code:
require "bulma-phlex"Use the Phlex components in your Rails views or any Ruby application that supports Phlex components.
The Button component provides a way to create styled buttons with various options for colors, sizes, and icons.
BulmaPhlex::Button(color: "primary", size: "large", icon: "fas fa-thumbs-up") { "Like" }The component can generate a button, anchor, or input element. By default it generates a <button>
element. If the href attribute is provided, it generates an <a> element. To generate an <input>
element, use the keyword argument input with a value of the type of input (button, reset, or submit).
Constructor Keyword Arguments:
color: Sets the button color (e.g., "primary", "link", "info", "success", "warning", "danger").mode: Sets the mode of the notification: "light" or "dark".size: Sets the button size: "small", "normal" (the default), "medium", or "large".responsive: Iftrue, makes the button responsive.fullwidth: Iftrue, makes the button full width.outlined: Iftrue, makes the button outlined.inverted: Iftrue, makes the button inverted.rounded: Iftrue, makes the button rounded.input: If provided, generates aninputelement instead of abutton. The value should be the type of input: "button", "reset", or "submit".icon: If provided, adds an icon to the button. Should be a string representing the icon class (e.g., "fa-solid fa-check").icon_left: If provided, adds an icon to the left of the button text. Should be a string representing the icon class (e.g., "fa-solid fa-check").icon_right: If provided, adds an icon to the right of the button text. Should be a string representing the icon class (e.g., "fa-solid fa-check").
Any additional HTML attributes passed to the constructor will be applied to the button element.
Cards are flexible containers that can display various types of content including headers and content sections.
render BulmaPhlex::Card.new do |card|
card.head("Card Title")
card.content do
"This is some card content"
end
card.footer_link("View", "/view", target: "_blank")
card.footer_link("Edit", "/edit", class: "has-text-primary")
endConstructor Arguments:
html_attributes: Any additional HTML attributes to be passed to the card container div.
Arguments for footer_link:
- text: the link text
- href: passed to the anchor's
hrefattribute - Any additional HTML attributes can be passed as keyword arguments.
Icons can be added to the links by passing an icon keyword argument with the icon class:
card.footer_link("View", "/view", icon: "fas fa-eye")The Columns component provides a way to create responsive columns layouts using Bulma's column classes. It generates the wrapping div with the columns class and handles all the options.
render BulmaPhlex::Columns.new(gap: 4, multiline: true) do
div(class: "column is-one-third") { "Column 1" }
div(class: "column is-one-third") { "Column 2" }
div(class: "column is-one-third") { "Column 3" }
endConstructor Keyword Arguments:
minimum_breakpoint: (Symbol, optional) Sets the minimum breakpoint for the columns; default is:tablet.multiline: (Boolean, optional) If true, allows the columns to wrap onto multiple lines.gap: (optional) Use an integer (0-8) to set the gap size between columns; use a hash keyed by breakpoints to set responsive gap sizes.centered: (Boolean, optional) If true, centers the columns.vcentered: (Boolean, optional) If true, vertically centers the columns.
The Dropdown component provides a flexible dropdown menu for navigation or actions. It supports both click-to-toggle (default, requires a Stimulus controller) and hoverable modes, as well as alignment and icon customization.
render BulmaPhlex::Dropdown.new("Next Actions...") do |dropdown|
dropdown.link "View Profile", "/profile"
dropdown.link "Go to Settings", "/settings"
dropdown.divider
dropdown.item("This is just a text item")
dropdown.item do
div(class: "has-text-weight-bold") { "This is a bold item" }
end
endOptions:
label(required): The dropdown button label.click(keyword): Stimulus controller name for click-to-toggle (default:"bulma-phlex--dropdown"). Set tofalsefor hoverable.alignment(keyword)::left(default),:right, or:up.icon(keyword): Icon class for the dropdown arrow (default:"fas fa-angle-down").html_attributes: Any additional HTML attributes to be passed to the dropdown container div.
Dropdown methods:
link(label, path): Adds a link item.item(content = nil, &block): Adds a custom item (string or block).divider: Adds a divider line.
The File Upload component provides the structure for a file input. The component generates the container and additional elements, then yields for the file input.
If the name keyword argument is set to true, the component will also generate the file name display element and add the necessary data attributes for it to work with the default Stimulus controller. The controller is not provided by this library, but you can create your own Stimulus controller to handle the logic. Here is an implementation of a Stimulus controller for Bulma file upload. If you want to use a custom builder for the data attributes, you can pass that in as well.
render BulmaPhlex::FileUpload.new(color: "primary") do |data_attributes|
input(type: "file", class: "file-input", data: data_attributes)
endConstructor Keyword Arguments:
color: Sets the color of the file inputsize: Sets the size of the file inputname: Iftrue, includes the file name display elementalign: Aligns the file input: right or centeredfullwidth: Iftrue, makes the file input full widthboxed: Iftrue, makes the file input boxeddata_attributes_builder: A custom builder for the data attributes used for Stimulus integration. If not provided, a default builder is used with the controller name "bulma-phlex--file-input-display".
Any additional HTML attributes passed to the constructor will be applied to the outer container div.
The Form Field component provides a way to create form fields with labels, inputs, and help text, following Bulma's form styling conventions. It also supports adding icons to the input, as well as tagging the field as a column or grid cell.
render BulmaPhlex::FormField.new(help: "We'll never share your email.") do |field|
field.label("Email Address")
field.control { input(name: "user[email_address]", type: "email") }
endThe label can be passed in as a string or created with a block:
field.label do
span { "Email Address" }
span(class: "has-text-danger") { "*" }
endConstructor Keyword Arguments:
icon_left: Icon class to display on the left side of the input (such asfas fa-user).icon_right: Icon class to display on the right side of the input.help: Help text to display below the field.column: When true, adds thecolumnclass to the container. Can also be a string specifying the column size (such astwo-thirds) or a hash with sizes by breakpoint (such as{ mobile: "full", desktop: "half" }).grid: When true, adds thecellclass to the container. Can also be a string specifying the heighth or width of the cell (such ascol-span-3).
The Grid component provides a flexible grid layout system using Bulma's grid classes.
render BulmaPhlex::Grid.new(minimum_column_width: 16) do
@tiles.each do |tile|
div(class: "cell") do
... render tile ...
end
end
endConstructor Keyword Arguments:
fixed_columns: (Integer, optional) Specifies a fixed number of columns for the grid.auto_count: (Boolean, optional) If true, the grid will automatically adjust the number of columns based on the breakpoint.minimum_column_width: (Integer 1-32, optional) Sets a minimum width for the columns in the grid.gap: (optional) Sets the gap size between grid items, from 1-8 with 0.5 increments.column_gap: (optional) Sets the column gap size between grid items, from 1-8 with 0.5 increments.row_gap: (optional) Sets the row gap size between grid items, from 1-8 with 0.5 increments.
The Hero component provides a large, full-width section for showcasing important content or calls to action, with support for different sizes and colors.
There are three ways to invoke the component:
- with a title and subtitle argument
- with a block for the hero body content
- invoke methods head, body, and footer on the yielded component and pass blocks to define each section
Additionally, both the size and color of the Hero can be specified through keyword arguments in the
constructor. Any additional HTML attributes given to the constructor will be added to the containing div.
render BulmaPhlex::Hero.new(title: "Welcome to My Site", subtitle: "We're glad you're here!", color: "primary")The Icon component provides a way to display icons using Font Awesome or other icon libraries, with support for different sizes and colors.
render BulmaPhlex::Icon.new("fas fa-user", size: "large", color: "primary")Constructor Arguments:
icon_class: (positional, required) The icon class to display (such asfas fa-user).size: (optional) The Bulma icon size: small, medium, large.color: (optional) The Bulma color class to apply.text_right: (optional) Text to display to the right of the icon.text_left: (optional) Text to display to the left of the icon.left: (optional) If true, adds theis-leftclass for use in form controls.right: (optional) If true, adds theis-rightclass for use in form controls.
Any additional HTML attributes are passed to the icon container span.
The Level component provides a flexible horizontal layout system with left and right alignment.
render BulmaPhlex::Level.new do |level|
level.left do
button(class: "button") { "Left" }
end
level.right do
button(class: "button") { "Right" }
end
level.right do
button(class: "button") { "Right 2" }
end
endPass in any HTML attributes to the constructor to have them applied to the level container div.
The Modal component provides a way to create modal dialogs with customizable content and styling options.
render BulmaPhlex::Modal.new do
div(class: "box") do
h1(class: "title") { "Modal Title" }
p { "This is the modal content." }
end
endConstructor Keyword Arguments:
data_attributes_builder: A builder object that responds tofor_container,for_background, andfor_close_button, which should return a hash of data attributes for the container, background, and close button, respectively. By default, this uses the nestedStimulusDataAttributesclass with the controller namebulma-phlex--modal. You can create your own builder to integrate with a different JavaScript framework or custom logic.
Any additional HTML attributes passed to the constructor will be applied to the modal container div. The modal can be toggled by adding or removing the is-active class on the container. (Nothing in the component adds the is-active class, so you will need to handle that with your own JavaScript or Stimulus controller.)
The NavigationBar component provides a responsive navigation header with support for branding, navigation links, and dropdown menus.
render BulmaPhlex::NavigationBar.new(color: "primary") do |navbar|
navbar.brand_item "My App", "/"
navbar.left do |menu|
menu.item "Home", "/"
menu.item "Products", "/products"
end
navbar.right do |menu|
menu.item "About", "/about"
menu.dropdown "Account" do |dropdown|
dropdown.header "User"
dropdown.item "Profile", "/profile"
dropdown.item "Settings", "/settings"
dropdown.divider
dropdown.item "Sign Out", "/logout"
end
end
endConstructor Keyword Arguments:
container: When true, wraps the content in a Bulma container. To set a constraint, such as "is-max-desktop", pass that string instead of true. (defaults to false)color: Sets the navbar color (e.g., "primary", "light", "dark").transparent: Iftrue, makes the navbar transparent.spaced: Iftrue, adds spacing to the navbar.shadow: Iftrue, adds a shadow to the navbar.
Any additional HTML attributes passed to the component will be applied to the <nav> element.
Note
Adding a container will limit the width of the Navigation Bar content according to Bulma's container rules. However, the background color of the navbar will still span the full width of the viewport.
The Notification component provides a way to display messages or alerts with customizable styles and a close button.
render BulmaPhlex::Notification.new(color: "info", delete: true) do
"This is an informational notification with a close button."
endThe delete keyword argument adds a close button to the notification. In addition to setting it to true, it can also be a hash of HTML attributes for the button, such as a data attribute to hook into a Stimulus controller.
render BulmaPhlex::Notification.new(color: "warning", delete: { data: { controller: "bulma-phlex--notification" } }) do
"This is a warning notification with a close button that works with a Stimulus controller."
endConstructor Keyword Arguments:
delete: (optional) When true, adds a close button to the notification. Can also be a hash of HTML attributes for the button.color: (optional) The Bulma color class to apply.mode: Sets the mode of the notification: "light" or "dark".
Any additional attributes are passed to the notification container div.
render BulmaPhlex::Notification.new(id: "my-notification", class: "ml-3") do
"This is a notification with custom id and class."
endThe Pagination component provides navigation controls for paginated content, including previous/next links, page number links, and a summary of items being displayed.
render BulmaPhlex::Pagination.new(@products, ->(page) { products_path(page: page) })Constructor Arguments:
pager: An object that responds to pagination methods (see below).path_builder: A lambda that takes a page number and returns the URL for that page. This is used to generate the links for the pagination controls.
Any additional HTML attributes passed to the constructor will be applied to the pagination container element.
In order to support pagination, the first argument in the constructor must repond with integers to the following:
- current_page
- total_pages
- per_page
- total_count
- previous_page (can be nil)
- next_page (can be nil)
The Progress Bar component provides a visual representation of progress or completion status, with support for different colors and sizes.
render BulmaPhlex::ProgressBar.new(color: "success", size: "large", value: 75, max: 100) { "75%" }Constructor Keyword Arguments:
color: (optional) The Bulma color class to apply.size: (optional) The Bulma size class to apply: small, medium, or large.html_attributes: Any additional HTML attributes to be passed to theprogresselement. Include thevalueandmaxattributes here to set the progress level.
Leaving out the value and max attributes will render an indeterminate progress bar, which can be used to indicate that a process is ongoing without specifying the exact progress.
The Table component provides a way to display data in rows and columns with customizable headers and formatting options.
users = User.all
render BulmaPhlex::Table.new(users, fullwidth: true, hoverable: true) do |table|
table.column "Name" do |user|
user.full_name
end
# use the symbol-to-proc shortcut!
table.column "Email", &:email
table.column "Actions" do |user|
link_to "Edit", edit_user_path(user), class: "button is-small"
end
endConstructor Keyword Arguments:
rows: the data for the table as an enumerable (anything that responds toeach)bordered: adds theis-borderedclass (boolean, defaults to false)striped: adds theis-stripedclass (boolean, defaults to false)narrow: adds theis-narrowclass (boolean, defaults to false)hoverable: adds theis-hoverableclass (boolean, defaults to false)fullwidth: adds theis-fullwidthclass (boolean, defaults to false)
Any additional HTML attributes passed to the constructor will be applied to the table element.
Arguments for column Method:
The column method takes the column name and any html attributes to be assigned to the table cell element. The block will be called with the row as the parameter.
Instead of calling column, you can also invoke the following methods to add date and icon columns:
Arguments for date_column:
- name: content for the
thelement format(keyword): the formatting options (will be passed tostrftime, defaults to "%Y-%m-%d")
table.date_column("Due Date", format: "%B %d, %Y") { |row| row.due_date }Arguments for conditional_icon:
The icon column is intended to show a boolean flag: a yes / no or an on / off. When the value is true the icon shows and when the value is false it does not.
- name: content for the
thelement icon_class(keyword): the icon to show (defaults to the Font Awesome check mark: "fas fa-check")
table.conditional_icon("Completed?", &:complete)
table.conditional_icon("Approved?", icon_class: "fas fa-thumbs-up") { |row| row.status == "Approved" }If the table should be paginated, invoke method paginate with a block that will return a path given a page number.
table.paginate do |page_number|
products_path(page: { number: page_number })
endThis generates the Bulma pagination component, providing navigation controls for paginated content. The rows argument is passed into the Pagination component to determine the current page, total pages, and other pagination details.
The Tabs component provides a way to toggle between different content sections using tabbed navigation, with support for icons and active state management.
Behavior of the tabs can be driven by the data attributes, which are assigned by the object passed in as the data_attributes_builder. By default, this will use the StimulusDataAttributes class with the controller name bulma-phlex--tabs. The controller is not provided by this library, but you can create your own Stimulus controller to handle the tab switching logic. Here is an implementation of a Stimulus controller for Bulma tabs.
render BulmaPhlex::Tabs.new(boxed: true) do |tabs|
tabs.tab(id: "profile", title: "Profile", active: true) do
"Profile content goes here"
end
tabs.tab(id: "settings", title: "Settings", icon: "fas fa-cog") do
"Settings content goes here"
end
tabs.tab(id: "notifications", title: "Notifications", icon: "fas fa-bell") do
"Notifications content goes here"
end
endConstructor Keyword Arguments:
align: Can becenteredorrightto align the tabs accordingly.size: Can besmall,medium, orlargeto set the size of the tabs.boxed: Iftrue, uses classic style tabs.toggle: Iftrue, makes the tabs look like buttons.rounded: Iftrue, makes the tabs look like buttons with the first and last rounded.fullwidth: Iftrue, makes the tabs take up the full width of the container.data_attributes_builder: Builder object that responds tofor_container,for_tab, andfor_content(with the latter two receiving the tabid). See the defaultStimulusDataAttributesfor an example.
Any additional HTML attributes passed to the component will be applied to the outer <div> element.
Keyword Arguments for tab Method:
id: The id to be assigned to the content. The tab will be assigned the same id with the suffix-tab.title: The name on the tab.active: Adds theis-activeclass to the tab and shows the related content. Non-active content is assigned theis-hiddenclass. Defaults tofalse.icon: Specify an optional icon class.
The Tag component provides a way to display small, colored labels or tags with customizable styles. The component generates either a span, a, or button element based on the provided options and HTML attributes.
If the HTML attributes include an href, an anchor (a) element is generated; if not and either the delete option is true or there is a data-action attribute, a button element is generated; otherwise, a span element is used.
render BulmaPhlex::Tag.new("New", color: "primary", rounded: true)
render BulmaPhlex::Tag.new("Sale", light: "danger")Constructor Arguments:
text: (positional, required) The tag text to display.color: (optional) The Bulma color class to apply.light: (optional) Use instead ofcolorto apply a light color variant.rounded: (optional) A boolean indicating whether the tag should have rounded corners.size: (optional) The Bulma tag size: normal, medium, or large.delete: (optional) A boolean indicating whether to include a delete button on the tag.
The Title component provide a way to display headings and subheadings with customizable sizes and styles.
render BulmaPhlex::Title.new("Hello World")
render BulmaPhlex::Title.new("Dr. Strangelove", size: 2, subtitle: "Or: How I Learned to Stop Worrying and Love the Bomb")Constructor Arguments:
text: (positional, required) The main title text to display.size: (optional) An integer from 1 to 6 indicating the size of the title. Corresponds to Bulma'sis-<size>classes.subtitle: (optional) The subtitle text to display below the main title.subtitle_size: (optional) An integer from 1 to 6 indicating the size of the subtitle. If not provided and a title size is given, it defaults tosize + 2.spaced: (optional) A boolean indicating whether to add theis-spacedclass to the title.
Important
The 0.8.0 release includes breaking changes. The namespace for the components has been changed from Components::Bulma to Components::BulmaPhlex.
This can generally be handled with a Find-and-Replace:
Find: Bulma::
Replace: BulmaPhlex::
Note that this change was also applied to the expected Stimulus controllers. References such as the Navigation bar have been updated from bulma--navigation-bar to bulma-phlex--navigation-bar.
Finally, the optional Rails extensions for the Card and Table components have been moved to the bulma-phlex-rails gem. If you are using this with Rails, you should use the bulma-phlex-rails gem. It provides both the component extensions as well as JavaScript for the Dropdown, Navigation Bar, and Tabs components.
After checking out the repo, run bundle install to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/RockSolt/bulma-phlex.
The gem is available as open source under the terms of the MIT License.
This leverages the Bulma CSS library and Phlex but is not endorsed or certified by either. We are fans of both and this makes using them together easier.