🎨 v0.17.0 — Layout & Display
What's New
StatComponent
A compact KPI tile for displaying a single metric at a glance. Accepts value:, label:, optional icon:, and a trend: delta (positive values render green/up, negative values render red/down). Pass trend_label: for a secondary annotation like "vs last month". Supports the standard color: theme prop to match your dashboard's visual language.
<%= midwest_stat(value: "1,284", label: "Total users", trend: "+12.5%", trend_label: "vs last month") %>ImageComponent
A responsive image component with native lazy loading, an optional click-to-zoom lightbox using a native <dialog>, and a poster: blur-up placeholder for progressive loading.
src:— the displayed image URLlarge:— full-size URL; presence enables the lightboxposter:— low-quality placeholder shown while the main image loadsnozoom: true— suppress the lightbox even whenlarge:is set
<%= midwest_image(src: photo.url, large: photo.full_url, poster: photo.thumb_url, alt: photo.caption) %>What Changed
AccordionComponent — multiple: option
Pass multiple: true to allow any number of items to be open at the same time. Each <details> element is rendered without a shared name attribute, opting out of the browser's native single-open behaviour. The default (multiple: false) is unchanged.
<%= midwest_accordion(multiple: true) do |a| %> <% a.with_item(label: "Section A") { "Content A" } %> <% a.with_item(label: "Section B") { "Content B" } %><% end %>CarouselComponent — loop: option
Pass loop: true for infinite arrow navigation. Clicking Next on the last slide wraps to the first; Previous on the first wraps to the last. Arrow buttons stay visible at both ends.
<%= midwest_carousel(loop: true) do |c| %> <% c.with_slide { "Slide 1" } %> <% c.with_slide { "Slide 2" } %><% end %>GridComponent — column_width: and column_gap: aliases
Two new props mirror the <midwest-grid> web component attribute names. column_width: replaces the positional width: kwarg and column_gap: replaces gap:. Both aliases accept a CSS string (e.g. "240px", "1.5rem") or a number (integer appends px, float appends rem). The original width: and gap: props remain fully functional.
<%= midwest_grid(column_width: 240, column_gap: "1rem") do %> ...<% end %>LayoutComponent — align:, align_content:, and height: :fill
Three new props give direct control over axis alignment and height:
align:— vertical alignment of columns within a row (:top,:center,:bottom,:baseline), maps toalign-itemsvia CSS custom property.align_content:— distribution of rows within the wrapper, maps toalign-content.height: :fill— adds aheight-fillclass that stretches the layout to 100% of its container. Useful inside fixed-height app shells.
<%= midwest_layout(type: :half, align: :center, height: :fill) do %> ...<% end %>TabsComponent — overflow scrolling with fade masks
Wide tab lists now scroll horizontally within their container. A Stimulus controller adds and removes can-scroll-left / can-scroll-right classes on connect and on scroll, which drive CSS gradient fade masks at the edges. The scrollbar itself is hidden. No API changes required.
AvatarComponent — two-character initials cap
Auto-initials derived from name: are now always capped at two characters. Previously, names with middle initials or hyphenated surnames could produce three-letter strings.
What Was Removed
Nothing removed.
Dev Process
Expanded test coverage
New unit and system test files added for every component touched in this release:
AccordionComponentTest,CarouselComponentTest,GridComponentTest,LayoutComponentTest,TabsComponentTest— unit tests for all new options.ImageComponentTest— full unit suite covering lazy loading, lightbox opt-in/opt-out, and poster rendering.StatComponentTest— tests for trend direction logic, icon rendering, and theme colour class.AvatarComponentTest— asserts initials are always ≤ 2 characters.GridComponentSystemTest,ImageComponentSystemTest— browser-level tests for grid layout and lightbox interaction.
New Lookbook previews
StatComponentPreview and ImageComponentPreview ship as new preview classes, each with scenario methods (default, with_trend / with_lightbox, with_icon / with_poster, no_zoom) and a playground method with live params.
Existing previews expanded: CarouselComponentPreview gains a loop scenario; GridComponentPreview gains column_gap, fit, and vertical scenarios; LayoutComponentPreview gains align and height_fill scenarios.