Technical Documentation: seyhunak/twitter-bootstrap-rails
βΉοΈ Provenance: Multi-Tier Ingestion Β· CodeWiki Reference
Overview (`README.md`)
twitter-bootstrap-rails
Integrates Bootstrap 5.3.8 into Rails Asset Pipeline. Supports Rails 8, 7, 6, 5.
Install
# Gemfile
gem "twitter-bootstrap-rails"bundle install
rails generate bootstrap:install staticGenerators
Every code snippet on the
Bootstrap 5.3 Introduction page
is reproducible from a command:
| Docs snippet | Command |
|---|---|
| Starter template | rails g bootstrap:starter |
CDN CSS <link> |
rails g bootstrap:cdn --css |
CDN JS bundle <script> |
rails g bootstrap:cdn --js |
Popper + bootstrap.js separately |
rails g bootstrap:cdn --separate-popper |
Important globals (doctype, lang, viewport) |
baked into every generated layout and the starter template |
# Install Bootstrap assets into the asset pipeline
rails g bootstrap:install static
# ...or load Bootstrap from the jsDelivr CDN instead
rails g bootstrap:install cdn
# Generate a Bootstrap layout
rails g bootstrap:layout application
# ...linking Bootstrap from the CDN, with Subresource Integrity
rails g bootstrap:layout application --cdn
# ...using Popper and bootstrap.js separately rather than the bundle
rails g bootstrap:layout application --cdn --separate-popper
# Write the starter template from the Bootstrap docs
rails g bootstrap:starter # -> public/bootstrap-starter.html
rails g bootstrap:starter --path=public/demo.html
# Print CDN tags to paste into a layout you already own (writes nothing)
rails g bootstrap:cdn
# Generate themed views for scaffold
rails g scaffold Task title:string done:boolean
rails db:migrate
rails g bootstrap:themed Tasksbootstrap:install cdn records the choice in config/initializers/bootstrap.rb,
so bootstrap:layout emits CDN tags by default afterwards. Pass --cdn or--no-cdn to override it per run.
Both asset pipelines are supported. On Sprockets, static adds require
directives to your manifests. On Propshaft (the Rails 8 default) there are no
directives to add, so the generated layout links the vendored files directly β
run rails g bootstrap:layout after bootstrap:install static either way.
The Bootstrap version and its CDN URLs and integrity hashes live in one place,Twitter::Bootstrap::Rails::BOOTSTRAP_CDN. No template hardcodes them.
Snippets
Every snippet published at
getbootstrap.com/docs/5.3/examples
β 62 of them across 12 categories β is a command. Each writes an .html.erb
partial into app/views/shared/:
rails g bootstrap:header # the first variant, "centered"
rails g bootstrap:header dark_search # a specific variant
rails g bootstrap:header --list # what's available, with descriptions| Command | Variants |
|---|---|
rails g bootstrap:header |
centered, nav_pills, with_auth_buttons, dark_search, light_search, grid_dropdown, double, dark_double |
rails g bootstrap:hero |
centered, centered_screenshot, with_image, signup_form, cropped_image, dark |
rails g bootstrap:features |
columns_with_icons, hanging_icons, custom_cards, icon_grid, with_title |
rails g bootstrap:sidebar |
dark, light, icon_only, collapsible, list_group |
rails g bootstrap:footer |
simple, with_brand, with_nav, columns, with_newsletter |
rails g bootstrap:dropdown |
simple, with_search, with_icons, calendar, mega_menu |
rails g bootstrap:list_group |
with_avatars, checkboxes, checkboxes_expanded, checkable, radios |
rails g bootstrap:modal |
sheet, confirm, whats_new, signup |
rails g bootstrap:badge |
pills, subtle, subtle_bordered, with_avatar, with_icons, with_avatar_divider |
rails g bootstrap:breadcrumb |
basic, with_icons, chevron, custom |
rails g bootstrap:button |
pills, grid, with_icons, loading, circle |
rails g bootstrap:jumbotron |
with_icon, placeholder, full_width, basic |
Variants are listed in the order they appear on the docs page, so the first one
in each row is the first example Bootstrap shows.
Options, on every snippet command:
| Option | Effect |
|---|---|
--list |
Print the variants with descriptions and exit, writing nothing |
--as=NAME |
Partial name to write (default: the generator name) |
--path=DIR |
Where to write it (default: app/views/shared) |
--no-icons |
Skip installing the shared icon sprite |
rails g bootstrap:footer columns --as=site_footer --path=app/views/layouts
# -> app/views/layouts/_site_footer.html.erbPlaceholder images
Five snippets (hero centered, hero centered_screenshot, hero with_image,hero cropped_image, features custom_cards) reference placeholder images that
only exist on Bootstrap's docs site, so they 404 until you point them at your own
assets. The generator warns you when you pick one.
Icons
36 of the 62 snippets use Bootstrap Icons through an SVG sprite. Those commands
also write _bootstrap_icons.html.erb next to the partial. Render it once,
near the top of `` in your layout, or those icons come out as empty boxes:
<%= render "shared/bootstrap_icons" %>Quick Start
rails new myapp
cd myapp
echo 'gem "twitter-bootstrap-rails"' >> Gemfile
bundle install
rails generate bootstrap:install static
rails generate scaffold Task title:string description:text completed:boolean
rails db:migrate
rails generate bootstrap:themed Tasks
rails generate bootstrap:layout application
rails serverRun bootstrap:layout even if you already have a layout β that step is what puts
Bootstrap's CSS and JS on the page.
Upgrading to 5.4.0
5.4.0 is a breaking release:
- Less is gone.
rails g bootstrap:install lessno longer exists; the
argument is nowstatic(default) orcdn. Bootstrap 5 has no Less build, and
theless-railsandexecjsdependencies have been dropped. - Glyphicons are gone, including the
glyphhelper. Bootstrap dropped them in
v4. The snippet generators ship Bootstrap Icons instead. - CoffeeScript support is gone, along with
--no-coffeescript. - The gem version no longer tracks the Bootstrap version.
Twitter::Bootstrap::Rails::BOOTSTRAP_VERSIONsays which Bootstrap ships.
If you are on Rails 8, note that bootstrap:install static previously left
Propshaft apps with no Bootstrap at all β that is fixed here. See the
CHANGELOG for the full list.
Sponsor
- Open Collective β back the project with a one-off or monthly contribution
- Patreon β become a patron
- Bootstrap 5 for Rails β release write-up on Patreon
Buy me a Coffee
β Support the Project
Contributors
Thanks to all contributors who are helping to make better.
Star History
License
MIT. Copyright (c) 2025 (since 2011) by Seyhun AkyΓΌrek
Superpowers Specs 2026 08 02 Bootstrap 53 Generators Design (`docs/superpowers/specs/2026-08-02-bootstrap-53-generators-design.md`)
Bootstrap 5.3.8 adaptation and Introduction-page snippet generators
Date: 2026-08-02
Status: Approved
Goal
Bring twitter-bootstrap-rails up to Bootstrap 5.3.8, and make every code snippet
on https://getbootstrap.com/docs/5.3/getting-started/introduction/ reproducible
through a rails g bootstrap:* command.
Background
The gem is currently inconsistent and partly broken:
app/assets/stylesheets/twitter-bootstrap-static/bootstrap.cssvendors Bootstrap
5.3.3; the generated layout CDN-pins 5.3.3 separately. Two places to bump.InstallGenerator#copy_bootstrap_assetsglobsvendor/assets/stylesheets/twitter/bootstrapandvendor/assets/javascripts/twitter/bootstrap. Neither path exists.Dir.glob
returns[], so the method creates two empty directories in the host app and
copies nothing, silently.Correction (verified during implementation): both paths exist and are
git-tracked, holding Bootstrap 5.3.3. The glob works. The real defects in this
area turned out to be:vendor/assets/stylesheets/twitter-bootstrap-static/bootstrap.css.erbis
Bootstrap 3.1.1 and occupies the same logical asset path as the Bootstrap 5app/assets/stylesheets/twitter-bootstrap-static/bootstrap.cssthatbootstrap_and_overrides.cssrequires. Whichever the pipeline resolves first wins.add_assetscallsFile.exist?on paths relative to the working directory
rather than the destination root, so an existingapplication.js/application.cssis never detected and gets overwritten by the gem's template.- On Propshaft apps there is no
require_selfanchor, so the require insertion
silently does nothing.
vendor/toolkit/**/*.lessandvendor/static-source/*.lessare the Bootstrap 3
Less source. Bootstrap 5 has no Less build. The gemspec still hard-depends onless-rails ~> 4.0andexecjs ~> 2.7, and ships apost_install_messagetelling
users to install a JavaScript runtime for Less compilation.app/assets/fonts/glyphicons-halflings-regular.*andapp/helpers/glyph_helper.rb
support Glyphicons, which Bootstrap dropped in v4.
Scope
In scope: the five snippets on the Introduction page only.
- CDN CSS
<link> - CDN JS bundle
<script> - The starter HTML template
- Popper +
bootstrap.jsas separate<script>tags - "Important globals" β HTML5 doctype,
<html lang>, viewport meta
Out of scope: component snippets from the rest of the Bootstrap docs (alerts, cards,
modals, ...). Those may become partials in a later pass.
Design
1. Single source of truth for upstream coordinates
lib/twitter/bootstrap/rails/version.rb carries the Bootstrap version and the CDN
URLs with their integrity hashes. No template hardcodes either.
module Twitter
module Bootstrap
module Rails
VERSION = "5.4.0"
BOOTSTRAP_VERSION = "5.3.8"
POPPER_VERSION = "2.11.8"
BOOTSTRAP_CDN = {
css: {
url: "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css",
integrity: "sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
},
bundle: {
url: "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js",
integrity: "sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
},
js: {
url: "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js",
integrity: "sha384-G/EV+4j2dNv+tEPo3++6LCgdCROaejBqfUeNjuKAiuXbjrxilcCdDz6ZAVfHWe1Y"
},
popper: {
url: "https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js",
integrity: "sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
}
}.freeze
end
end
endBumping Bootstrap becomes a one-file change plus re-vendoring the two dist files.
A shared module Bootstrap::Generators::CdnTags renders tag strings from this hash
and is mixed into the generators that need them. It exposes css_tag,bundle_tag, popper_tag, and js_tag, each returning the exact markup from the
docs page.
2. Snippet-to-command mapping
| Docs snippet | Command |
|---|---|
| Starter template | rails g bootstrap:starter |
| Important globals | baked into every layout and starter template |
| CDN CSS link | rails g bootstrap:layout --cdn |
| CDN JS bundle | rails g bootstrap:layout --cdn |
| Popper + bootstrap.js separately | rails g bootstrap:layout --cdn --separate-popper |
| Any of the above, as text | rails g bootstrap:cdn |
3. `bootstrap:install`
Signature: rails g bootstrap:install [static|cdn], default static.
static(default) vendors Bootstrap 5.3.8 into the host app's asset pipeline and
adds therequirelines to the CSS/JS manifests.cdnskips vendoring entirely and writesconfig/initializers/bootstrap.rb
containingTwitter::Bootstrap::Rails.asset_mode = :cdn.bootstrap:layoutreadsTwitter::Bootstrap::Rails.asset_modeto pick its default; passing--cdnor--no-cdnoverrides it. The accessor is defined inlib/twitter/bootstrap/rails/bootstrap.rbas anmattr_accessordefaulting to:static, so the layout generator works whether or not the initializer exists.
Behaviour changes:
copy_bootstrap_assetsis fixed to read from paths that exist. Bootstrap 5.3.8'sbootstrap.min.cssandbootstrap.bundle.min.jsare downloaded from jsDelivr,
verified against the integrity hashes above, and committed tovendor/assets/stylesheets/twitter-bootstrap-static/andvendor/assets/javascripts/twitter/bootstrap/respectively. The generator raises
a clear error if a source file is missing rather than creating empty directories.- The
lessargument value, thebootstrap_and_overrides.lesstemplate, the--no-coffeescriptoption, and thebootstrap.coffeetemplate are removed.
4. `bootstrap:layout`
Gains two options:
--cdn/--no-cdnβ emit the jsDelivr<link>/<script>tags with integrity
andcrossoriginattributes, instead ofstylesheet_link_tag/javascript_include_tag. Default comes from the mode recorded bybootstrap:install, falling back to vendored.--separate-popperβ with--cdn, emit the Popper +bootstrap.min.jspair
instead of the single bundle. Ignored with a warning when--cdnis not set,
since the vendored path ships the bundle.
All three template engines (erb, haml, slim) support both options.
5. `bootstrap:starter` (new)
Writes the Introduction page's starter template to public/bootstrap-starter.html
β a standalone HTML document with no ERB, so public/ is where it can be opened
directly in a browser. --path=PATH overrides the destination. The file is the docs
snippet verbatim, with the version and integrity values interpolated from the
constants.
6. `bootstrap:cdn` (new)
Prints tags to stdout rather than writing a file, for pasting into a layout the user
already owns. Writes nothing to disk.
rails g bootstrap:cdnβ CSS link + JS bundle scriptrails g bootstrap:cdn --cssβ CSS link onlyrails g bootstrap:cdn --jsβ JS bundle script onlyrails g bootstrap:cdn --separate-popperβ Popper + bootstrap.js pair
7. Removals
Deleted outright, since nothing in Bootstrap 5 uses them:
vendor/toolkit/(Bootstrap 3 Less source)vendor/static-source/(Bootstrap 3 Less source)app/assets/fonts/glyphicons-halflings-regular.*app/helpers/glyph_helper.rbandspec/lib/twitter_bootstrap_rails/glyph_helper_spec.rblib/generators/bootstrap/install/templates/bootstrap_and_overrides.lesslib/generators/bootstrap/install/templates/bootstrap.coffee- gemspec: the
less-railsandexecjsdependencies, andpost_install_message
GlyphHelper is removed rather than deprecated because its icon font is being
deleted in the same pass; leaving the helper would emit markup for glyphs that no
longer resolve.
Versioning
Gem version goes to 5.4.0. Dropping Less, Glyphicons, and the less install
argument breaks existing users, so this cannot be a patch. The gem version
consequently stops tracking the Bootstrap version; BOOTSTRAP_VERSION is the
authoritative statement of which Bootstrap ships.
Testing
New specs under spec/lib/generators/, using Rails::Generators::TestCase against
a tmp destination root:
install_generator_specβstaticvendors both dist files into the destination
and inserts the manifestrequirelines;cdnvendors nothing and writes the
initializer; a missing vendored source raises rather than silently no-opping.layout_generator_specβ default emitsstylesheet_link_tag;--cdnemits the
CSS link and bundle script with the exact URL and integrity from the constants;--cdn --separate-popperemits the Popper andbootstrap.min.jspair and no
bundle;--separate-popperwithout--cdnwarns. Repeated per engine.starter_generator_specβ output is byte-identical to the docs snippet once the
version and hashes are interpolated;--pathis honoured.cdn_generator_specβ each flag prints the expected tags and writes no file.- A guard spec asserting no template contains a hardcoded
bootstrap@version
string, so the constants stay the only source.
Existing helper specs continue to run unchanged, minus the deleted glyph spec.
Documentation
README: update the generator table with bootstrap:starter and bootstrap:cdn and
the new bootstrap:layout options. CHANGELOG: a 5.4.0 entry with a Breaking Changes
section covering the Less, Glyphicons, coffeescript, and bootstrap:install less
removals, and the fixed vendoring bug.
--- METRICS ---
- Files Extracted: 2
- Estimated Token Budget: ~4551 tokens
- Canonical Reference: https://codewiki.google/github.com/seyhunak/twitter-bootstrap-rails