Design System

Midwest

A beautiful, complete Design System

Unabridged Software

The Goals of Midwest

Make it easy to create beautiful, unique experiences.

  1. 1

    HTML first
    CSS second
    Rails/Turbo third
    JS if needed

  2. 2

    A Distinct Visual Language - doesn’t feel like Tailwind.

  3. 3

    One, singular dependency, turbo + stimulus as possible peers.

  4. 4

    Deeeeeep Rails integration.

History

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.

Lessons Learned

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:

Alert circle

JS-first by nature

So many things were imperative and framework-specific

Cloud

Heavy runtime deps

Stencil, anime.js, Shepherd.js, and more

Hammer

Poor Server side language ergonomics

rails, laravel, static site generators, no server-side rendering

Layers

Maintenance burden

8 packages, Lerna monorepo, constant versioning churn

The REMIIIIIX

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.

Today

ViewComponent Library

43+
Components
v0.19
Current Version
+95%
Test Coverage
YEP
Rails + Bridgetown Integration tests
Checkmark circle
Built on ViewComponent — High quality and server-rendered
Checkmark circle
Ships with Midwest::FormBuilder — first-class Rails form integration
Checkmark circle
Supports Rails 7.1, 8.0 and Bridgetown v1, v2 — MIT licensed
Philosophy · 1 of 4

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! -->
Philosophy · 2 of 4

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
Close
No React/Vue
Close
No jQuery
Close
No UI kit wrappers
Close
No 300-package dependency trees
Philosophy · 3 of 4

HTML first.

Midwest components output valid, accessible HTML aaaand you'd have to work really hard to break it.

Code

Buttons

`<button>` elements, not `<div>` click handlers

Document

Dialogs

Native HTML `<dialog>` element

List

Form fields

Proper `<label>` associations always included

Apps

Tabs

ARIA tablist/tab/tabpanel pattern

Checkmark circle

Keyboard nav

Built in to every interactive component

Globe

Screen readers

Semantic roles and labels on every component

Philosophy · 4 of 4

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 { ... }
Shield

Zero style leakage — components don't bleed into each other

Code

No CSS-in-JS — plain CSS, cacheable and inspectable

Settings

BEM-like naming: midwest-button, variant-primary, size-lg

Sparkles

13 color themes with full dark mode via CSS custom properties

Flash

Zero runtime style computation

Architecture

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
Architecture

When JavaScript is necessary, Stimulus keeps it honest.

Code

Co-located with their component (sidecar pattern)

Shield

TypeScript with strict mode

Cube

Scoped — one controller per component, no globals

Layers

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
What's In The Box

43+ components at v0.19

Grid

Layout & Structure

grid, layout, card

Apps

Navigation

breadcrumbs, dropdown, tabs, pagination, mobile nav

Flash

Buttons & Actions

button (loading, confirm, tooltip), rating

Document

Content Display

badge, banner, callout, stat, testimonial, timeline, prose, image, video, skeleton, progress bar, empty state, avatar

Sparkles

Interactive

carousel, dialog, confirmation, popover, tooltip, countdown

Checkmark circle

Forms (15 variants)

input, select, checkbox, radio, switch, range, file, autocomplete, card option, collection, field group, label, live summary

Forms

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 %>
Alert circle

Validation errors render inline, no extra wiring

Document

live_summary shows a live validation summary

Flash

Works with Turbo streams and standard form submissions

Hammer

Backed by Midwest::FormBuilder — a first-class Rails form builder

Compatibility

Not just Rails.

Midwest runs on Bridgetown (Ruby-based static site generator) v1 and v2.

Server

Rails Apps

  • Full-stack, Hotwire, Turbo
  • Server-rendered components
  • Form builder included
  • Rails 7.1 and 8.0
Globe

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.

Quality

We test like it matters, because it does.

43+
Unit tests per component
8
Framework combinations
97%
Test coverage
4
Lint tools
Checkmark circle

ViewComponent::TestHelpers for unit tests

Checkmark circle

Capybara + Playwright system tests — real browser

Checkmark circle

Rails 7.1 + 8.0, Bridgetown v1 + v2, Ruby 3.3 + 3.4

Checkmark circle

RuboCop (StandardRB), ESLint, Stylelint, erb-lint

v0.19

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
Market

The Rails renaissance is real. The design system ecosystem hasn't caught up.

shadcn/ui

React-only

daisyUI

Tailwind-only, no component logic

Bootstrap

Aging and JS-heavy

Material/Ant

React/Vue ecosystems

Midwest is the only production-quality, Rails-native design system that actually ships.

Audience

Built for teams who choose Rails deliberately.

Server

Rails shops

UI consistency without adopting a JS framework

Flash

Indie devs & small agencies

Move fast without sacrificing quality

Layers

JS library migrants

Teams moving away from Web Components or heavy JS libs

Globe

Bridgetown users

Marketing sites, documentation, portfolios

Code

ERB & Tailwind survivors

Anyone who's stared at raw markup and thought 'there has to be a better way'

Diamond

Quality-focused teams

Who want tested, accessible, production-grade components

Business Model

Open core. Pro extensions. Services.

Logo github
Open Source
  • Checkmark circle
    MIT license, freely available
  • Checkmark circle
    Community-driven contributions
  • Checkmark circle
    Powers Unabridged client work
Diamond
Pro Components
  • Checkmark circle
    Data tables — sort, filter, paginate
  • Checkmark circle
    Calendar & date pickers
  • Checkmark circle
    Chart components
  • Checkmark circle
    Kanban & drag-and-drop
Star
Services
  • Checkmark circle
    Priority support subscriptions
  • Checkmark circle
    Custom component development
  • Checkmark circle
    Design system audits & migrations
  • Checkmark circle
    Starter kits & themes
Getting Started

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" %>
Community

Midwest is actively developed and open to the community.

The best way to contribute is to use it and report what's missing.

Logo github

GitHub

Source

github.com/unabridgedsoftware/midwest

Code

Demo App

Local

Run locally with bin/dev → localhost:4000

Apps

Lookbook

Docs

Component previews at /lookbook

Document

Issues & PRs

Contribute

Especially 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.

v0.19 MIT 43+ components