Bh · Bootstrap Helpers
Bootstrap 6 in a Rails app, with the markup already written.
Every component, drawn and explained →
Bootstrap is a fine framework that asks for a lot of HTML. Bh answers with a form builder that dresses every field a page can ask for, helpers for the components Bootstrap ships behavior for and no markup — a combobox, a 6-digit code, a dialog, a toast, a thread of messages — and the one stylesheet and one script that carry them, served by the engine.
How to install
gem install bh
gem 'bh', '~> 6.9.0'
~> 6.9.0 stops short of 6.10, which is the pin to hold while this line still breaks on a
minor rather than on a major.
The stylesheet and the script
With the gem in the bundle an app serves /bh/css/bh.css and /bh/js/bh.js itself, at the
prefix its engine is mounted at. A layout links both:
<link rel='stylesheet' href='<%= Bh::Engine::PREFIX %>css/bh.css'>
<script type='module' src='<%= Bh::Engine::PREFIX %>js/bh.js'></script>
The palettes
Nine of them, served at /bh/theme/<name>.css and linked one at a time, after the stylesheet:
bootstrap, dawn, dracula, gruvbox, monokai, nord, one_dark, solarized,
tokyo_night. Each restates all thirteen steps of every Bootstrap family it repaints, plus
--bs-white, --bs-black and the three text tones. Every accent clears 3:1 against its label
and every text tone 4:1, in both modes.
bootstrap declares nothing: upstream's palette comes back by dropping the others' block
rather than by writing one, and it is named so a toggle can reach it — a reader who rotates
through nine and never finds the one the pages started in has been shown a door with no handle
on the inside.
The scheme controller does the swapping, and the choice belongs to the reader:
<button type='button' data-controller='scheme' data-action='scheme#rotate'
data-scheme-themes-value='["bootstrap","dawn","dracula","gruvbox","monokai","nord","one_dark","solarized","tokyo_night"]'
data-scheme-path-value='/bh/theme' data-scheme-storage-value='scheme'>
Another palette
</button>
A click moves to another palette and into the mode it is not in. Put the stored choice back before the first paint, from the layout's own script: a controller connects far too late for that, and the page would otherwise flash the palette the server chose.
What you get
class ApplicationController < ActionController::Base
default_form_builder Bh::FormBuilder
end
fieldset label submit button |
the form's furniture, with the pill Bootstrap draws |
every *_field, text_area, select, check |
dressed at one size, so a view says which kind and nothing about how it looks |
phone_field |
a North American number, shaped 555-555-5555 as it is typed |
price_field percentage_field |
money and a share of a hundred, typed into Bootstrap's adorned control |
pin_field |
one real field drawn as six slots, offered by the phone from the text that brought it |
combobox |
a <select> drawn as a searchable menu, still the one thing the form submits |
dialog |
a link and the <dialog> it opens, sharing an id made from the link's own words |
toasts |
the flash as toasts, held while they are read |
chat_with |
a thread of bubbles, and the field that posts the next one |
confirm_button_to |
a button whose form is sent only where the question it carries is answered yes |
tooltip_data |
the data an element wearing a tooltip takes |
| 22 Stimulus controllers | registered by the bundle, called by data-controller |
| 9 palettes | served at /bh/theme/, swapped by the scheme controller |
The page above draws every one of them beside the line of Ruby that produces it.
Trying it out
The gem carries a dummy app drawing every helper on one page, and a bin/rails at the root, so
there is no cd first. From the root of a clone:
bin/setup
rails s
localhost:3000 is every component at once, and ?flash=1 adds the toasts.
Elsewhere
- The page — every component, and how to reach it
- API reference — built from what RubyGems holds
- CHANGELOG — what each release is, and which of the three it is
MIT licensed.
