π·οΈ v0.18.0 β Data Forms & Notifications
What's New
TagInputComponent
A multi-value text field where each entered value renders as a removable badge inline with the input. Built as a thin subclass of AutocompleteComponent with free_form: true baked in. Supports free-form entry, paste-to-split on comma or newline, Backspace to remove the last tag, and an optional choices: list to constrain input to known values.
<%= midwest_tag_input(name: "tags", label: "Topics", placeholder: "Add a tagβ¦") %>NotificationComponent
A transient, self-dismissing feedback toast. Renders a slide-in notification with an optional title:, a state: (:success, :error, :warning, :info, or :default) that picks a contextual icon and color, and a countdown: integer for automatic dismissal via CountdownTimerComponent. Use midwest_notifications_container(placement:) in your layout to create a fixed Turbo Frame, then push toasts server-side with turbo_stream.prepend 'midwest-notifications'.
<%= midwest_notification(title: "Saved!", state: :success, countdown: 5) do %> Your changes have been saved.<% end %>Form::ColorPickerComponent
A palette-based color selector restricted to the Midwest design system's named theme colors. Accepts val: for the initially selected color, notransparent: true to suppress the transparent swatch, and custom: true to add a rainbow swatch that opens the native color picker. When a custom hex is chosen a 13-step --theme-{0β12}-channels CSS custom property scale is generated and applied inline. Dispatches a color:update Stimulus event on selection.
<%= midwest_form_color_picker(name: "theme_color", val: "blue") %>What Changed
ButtonGroupComponent β joined button rows and segmented controls
A new component that renders a set of buttons as a single joined visual unit. All buttons in the group share the same variant: and size: unless overridden per button. Pass pill: true for fully rounded outer edges. Wire selection state with aria-pressed: "true" on the active button.
<%= midwest_button_group do |g| %> <% g.with_button(label: "Day", aria: { pressed: "true" }) %> <% g.with_button(label: "Week") %> <% g.with_button(label: "Month") %><% end %>ProgressBarComponent β circular variant
Pass variant: :circular for a donut ring indicator. Well-suited for compact spaces: profile completeness scores, upload progress overlays, and dashboard KPI tiles. Add show_value: true to render the percentage centred inside the ring.
<%= midwest_progress_bar(value: 72, variant: :circular, show_value: true, label: "Profile complete") %>PaginationComponent β cursor-based mode
Accept next_cursor: and prev_cursor: tokens alongside a cursor_url: proc instead of the offset-based current_page: / total_pages: model. Set either cursor to nil to disable the corresponding arrow (first or last page). Useful with cursor-based APIs and infinite scroll patterns.
<%= midwest_pagination( next_cursor: @pagy.next_cursor, prev_cursor: @pagy.prev_cursor, cursor_url: ->(c) { products_path(cursor: c) }) %>Form::InputComponent β caps-lock detection and number steppers
Two new type:-specific enhancements:
show_caps_lock: trueontype: :passwordfields displays a visible warning badge when the user's Caps Lock key is active, detected viaKeyboardEvent.getModifierState. The badge is hidden until a keyup event confirms the state.increments: trueontype: :numberfields replaces the browser's native spinners with explicit β/+ stepper buttons. Respectsmin:,max:, andstep:values passed throughhtml_options.
<%= midwest_input(name: "password", type: :password, show_caps_lock: true, label: "Password") %><%= midwest_input(name: "quantity", type: :number, increments: true, label: "Qty", html_options: { min: 1, max: 99 }) %>What Was Removed
Midwest::ColorPickerComponent relocated to Midwest::Form::ColorPickerComponent
The color picker has moved from the top-level app/components/midwest/ directory into the form/ subdirectory to align with all other form controls. Update any direct class references and require paths accordingly. The view helper (midwest_form_color_picker) is unchanged.
Dev Process
Accessibility panel consolidated
The Lookbook accessibility panel (_accessibility.html.erb) was rewritten and moved entirely into the main gem, removing the demo-side overrides for _accessibility.html.erb, _assets.html.erb, _figma.html.erb, and _page_theme.html.erb. The panel now covers contrast ratios, ARIA roles, and theme token inspection in a single, maintained location.
Expanded test coverage
New unit test files shipping in this release:
NotificationComponentTestβ state variants, countdown behavior, close action, animation classes.TagInputComponentTestβ free-form entry, constrained choices, paste splitting, pre-populated values.Form::ColorPickerComponentTestβ palette rendering, transparent suppression, custom hex flow, hidden input wiring.ButtonGroupComponentTestβ default and segmented rendering, size forwarding, pill modifier.ProgressBarComponentTestβ circular variant,show_value, indeterminate state.PaginationComponentTestβ cursor-based mode, nil cursor disabling arrows.Form::InputComponentTestβ caps-lock markup, increment stepper bounds enforcement.Form::AutocompleteComponentTestβ free-form mode additions, tag creation and removal.
New and updated Lookbook previews
TagInputComponentPreview, NotificationComponentPreview, ColorPickerComponentPreview, and ButtonGroupComponentPreview are all new. ProgressBarComponentPreview gains a circular scenario; PaginationComponentPreview gains cursor_based; InputComponentPreview gains password_caps_lock and number_increments.