HTML first
CSS second
Rails/Turbo third
JS if needed
Midwest
A beautiful, complete Design System
Unabridged Software
The Goals of Midwest
Make it easy to create beautiful, unique experiences.
-
1
-
2
A Distinct Visual Language - doesn’t feel like Tailwind.
-
3
One, singular dependency, turbo + stimulus as possible peers.
-
4
Deeeeeep Rails integration.
Before my time at Unabridged, I was iterating on @midwest-design
A Stencil-based monorepo of Web Components, shipped as npm packages:
@midwest-design/core
Layout, navigation, UI primitives
@midwest-design/forms
Input validation, field matching
@midwest-design/motion
Animations, carousels, parallax
@midwest-design/media
Images, video, 360° panoramic viewers
@midwest-design/audio
Web Audio API, MIDI, visualizers
@midwest-design/helpers
Modals, maps, markdown, guided tours
I used it on several projects while I was freelancing.
Universal Web Components was inundated with JS.
The web platform has evolved rapidly in the last few years, and many of the problems Web Components were designed to solve have been addressed natively by browsers. As a result, the library became weighed down by JavaScript that was no longer necessary — leading to performance issues, maintenance overhead, and a less-than-ideal developer experience.
Specific issues I ran into:
JS-first by nature
So many things were imperative and framework-specific
Heavy runtime deps
Stencil, anime.js, Shepherd.js, and more
Poor Server side language ergonomics
rails, laravel, static site generators, no server-side rendering
Maintenance burden
8 packages, Lerna monorepo, constant versioning churn
I wanted to translate my past work into a design system/component library.
Not a JavaScript component framework that kinda works with Rails.
Not a wrapper around an npm design system.
Not another port of Bootstrap or Material.
Something that includes multiple facets of design. Including motion design, sound design, and sensory input.
ViewComponent Library
Custom JavaScript LAST
Modern HTML and CSS handles animations, layout, theming, and state — without any JavaScript. JS in Midwest exists only to bridge the gaps the platform hasn't closed yet — always as a progressive enhancement, never a prerequisite.
React Accordion — ~100 lines JS compiled
const [open, setOpen] = useState(false)
const handleToggle = () => {
setOpen(!open)
}
return (
<div onClick={handleToggle}>
<div className="header">
{title}
</div>
{open && (
<div className="content">
{children}
</div>
)}
</div>
)
Midwest Accordion — Zero JS
<details>
<summary>
Title
</summary>
<div>
Content
</div>
</details>
<!-- Not bad! -->
No External Dependencies
| Dependency | Why It Exists |
|---|---|
| @hotwired/stimulus | Lightweight JS controller framework — already in every Rails 7+ app |
| @hotwired/turbo | Progressively enhanced page navigation and partial updates — already in every Rails 7+ app |
| opt_struct | For organizing component options |
HTML first.
Midwest components output valid, accessible HTML aaaand you'd have to work really hard to break it.
Buttons
`<button>` elements, not `<div>` click handlers
Dialogs
Native HTML `<dialog>` element
Form fields
Proper `<label>` associations always included
Tabs
ARIA tablist/tab/tabpanel pattern
Keyboard nav
Built in to every interactive component
Screen readers
Semantic roles and labels on every component
Tailwind CSS with real architectural discipline.
Styles are built with Tailwind's @apply directive inside dedicated CSS layers — one per component.
@layer midwest.components.button { ... }
@layer midwest.components.form-group { ... }
@layer midwest.components.dropdown { ... }
@layer midwest.components.card { ... }
@layer midwest.components.badge { ... }
Zero style leakage — components don't bleed into each other
No CSS-in-JS — plain CSS, cacheable and inspectable
BEM-like naming: midwest-button, variant-primary, size-lg
13 color themes with full dark mode via CSS custom properties
Zero runtime style computation
Components work without JavaScript. JS makes them better.
| Component | Without JS | With JS |
|---|---|---|
| Accordion | Native <details>/<summary> | Animated expand/collapse |
| Button | Submits form, follows link | Loading spinner on async action |
| Carousel | Static scroll container | Keyboard navigation, swipe |
| Dropdown | Native <select> fallback | Focus-managed floating menu |
| Dialog | Hidden content block | Proper focus trap, backdrop |
| Tooltip | title attribute | Floating, positioned popover |
When JavaScript is necessary, Stimulus keeps it honest.
Co-located with their component (sidecar pattern)
TypeScript with strict mode
Scoped — one controller per component, no globals
Disposable — component renders without JS; Stimulus attaches after
Simple component — no JS needed
badge_component/ badge_component.html.erb badge_component.css
Interactive — JS added only where needed
button_component/ button_component.html.erb button_component.css button_component_controller.ts
43+ components at v0.19
Layout & Structure
grid, layout, card
Navigation
breadcrumbs, dropdown, tabs, pagination, mobile nav
Buttons & Actions
button (loading, confirm, tooltip), rating
Content Display
badge, banner, callout, stat, testimonial, timeline, prose, image, video, skeleton, progress bar, empty state, avatar
Interactive
carousel, dialog, confirmation, popover, tooltip, countdown
Forms (15 variants)
input, select, checkbox, radio, switch, range, file, autocomplete, card option, collection, field group, label, live summary
Rails form ergonomics, out of the box.
<%= midwest_form_with model: @user do |f| %>
<%= f.midwest_input :email,
label: "Email address" %>
<%= f.midwest_input :password,
type: :password %>
<%= f.midwest_select :role,
collection: roles %>
<%= f.midwest_switch
:notifications_enabled %>
<%= f.midwest_submit "Save changes" %>
<% end %>
Validation errors render inline, no extra wiring
live_summary shows a live validation summary
Works with Turbo streams and standard form submissions
Backed by Midwest::FormBuilder — a first-class Rails form builder
Not just Rails.
Midwest runs on Bridgetown (Ruby-based static site generator) v1 and v2.
Rails Apps
- Full-stack, Hotwire, Turbo
- Server-rendered components
- Form builder included
- Rails 7.1 and 8.0
Bridgetown Sites
- Static sites and marketing sites
- Documentation and portfolios
- Same component library
- Bridgetown v1 and v2
One gem. One design language. One source of truth.
We test like it matters, because it does.
ViewComponent::TestHelpers for unit tests
Capybara + Playwright system tests — real browser
Rails 7.1 + 8.0, Bridgetown v1 + v2, Ruby 3.3 + 3.4
RuboCop (StandardRB), ESLint, Stylelint, erb-lint
What's shipped, what's coming.
- Accordion animation improvements
- Grid and carousel enhancements
- Images component with lazy loading
- Stats display component
- Avatar two-character rendering fix
- Dark mode table fixes
- Data table component
- Command palette
- Notification/toast system
- Interactive docs (Storybook-style)
- Stable 1.0 API
The Rails renaissance is real. The design system ecosystem hasn't caught up.
shadcn/ui
React-onlydaisyUI
Tailwind-only, no component logicBootstrap
Aging and JS-heavyMaterial/Ant
React/Vue ecosystemsMidwest is the only production-quality, Rails-native design system that actually ships.
Built for teams who choose Rails deliberately.
Rails shops
UI consistency without adopting a JS framework
Indie devs & small agencies
Move fast without sacrificing quality
JS library migrants
Teams moving away from Web Components or heavy JS libs
Bridgetown users
Marketing sites, documentation, portfolios
ERB & Tailwind survivors
Anyone who's stared at raw markup and thought 'there has to be a better way'
Quality-focused teams
Who want tested, accessible, production-grade components
Open core. Pro extensions. Services.
-
MIT license, freely available
-
Community-driven contributions
-
Powers Unabridged client work
-
Data tables — sort, filter, paginate
-
Calendar & date pickers
-
Chart components
-
Kanban & drag-and-drop
-
Priority support subscriptions
-
Custom component development
-
Design system audits & migrations
-
Starter kits & themes
Starting with Midwest is one line.
Gemfile
gem "midwest"
JavaScript
yarn add @unabridgedsoftware/midwest
Components, styles, and JavaScript all available immediately. Migration can be gradual — Midwest lives alongside existing markup and can be adopted one view at a time.
Before
<div class="px-4 py-2 rounded bg-blue-600
text-white text-sm font-medium">
Save changes
</div>
After
<%= midwest_button "Save changes" %>
Midwest is actively developed and open to the community.
The best way to contribute is to use it and report what's missing.
GitHub
Sourcegithub.com/unabridgedsoftware/midwest
Demo App
LocalRun locally with bin/dev → localhost:4000
Lookbook
DocsComponent previews at /lookbook
Issues & PRs
ContributeEspecially accessibility improvements and new components
Midwest
Less JavaScript. More Rails. Better UI.
Server-rendered components. Modern CSS. A design language that grows with your product.
Built for the way Rails was meant to be used.