Project

bh

0.2
Low commit activity in last 3 years
A long-lived project that still receives updates
A form builder that dresses every field a page asks 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 script that carry them, served by the engine.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 8.1
 Project Readme

Bh · Bootstrap Helpers

Bootstrap 6 in a Rails app, with the markup already written.

Every component Bh draws, on one page

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.