♿ v0.23.0 — Content, Accessibility & MCP Diagnostics
This release leans into content rendering, accessibility, and viewport-aware behavior — plus four new MCP tools that suggest, diagnose, and scaffold components for AI-assisted workflows.
What's New
MarkdownComponent
Server-side Markdown rendering via Commonmarker, styled with the Midwest prose typography system out of the box. Supports GitHub-flavored extensions (tables, strikethrough, autolinks, task lists) and an optional unsafe: true mode for raw HTML passthrough.
<%= midwest_markdown(unsafe: false) do %> # Release Notes Render rich text with **full prose typography** and GFM extensions. - Tables, strikethrough, autolinks - Task lists and blockquotes<% end %>SocialPreviewComponent
Platform-accurate previews of how a post will look on Facebook, Twitter/X, LinkedIn, and Instagram. The parent SocialPreviewComponent orchestrates platform sub-components (each extending SocialPreview::BasePlatformComponent) via slots, with image mosaic grids, link preview cards, avatar layouts, and per-platform styling.
<%= midwest_social_preview( platforms: [:facebook, :twitter, :linkedin, :instagram], name: "Jane Smith", handle: "@janesmith", content_text: "Excited to share our latest design system update!", avatar_url: avatar_url, images: [hero_image_url]) %>IntersectionObserverComponent
A declarative wrapper around the browser's IntersectionObserver — toggle a class, run an action, or reveal content as an element scrolls into view. Configure threshold, root_margin, once, and the visible_class that's applied while intersecting; no custom JavaScript required.
<%= midwest_intersection_observer(threshold: 0.5, once: true, visible_class: "reveal-in") do %> <%= midwest_card { "I fade in when half of me is visible." } %><% end %>OnboardingComponent
Native, dependency-free product tours. A parent OnboardingComponent orchestrates nested Onboarding::StepComponent slots through a Stimulus tour engine: dimmed overlay, target highlighting, a positioned card with an arrow, Back/Next/Done controls, keyboard navigation (← →, Escape), focus trapping, and optional exit confirmation.
<%= midwest_onboarding(id: "demo-tour") do |o| %> <% o.with_trigger do %> <%= midwest_button("data-action": "midwest-onboarding#start") { "Start tour" } %> <% end %> <% o.with_step(title: "Welcome") do %> <p>This quick tour shows you around.</p> <% end %> <% o.with_step(title: "Your dashboard", selector: "#dashboard", position: :bottom) do %> <p>Your key metrics live here.</p> <% end %><% end %>SkipLinkComponent
A skip-navigation link for keyboard users — visually hidden until focused, then jumps focus past repetitive navigation to the main content. Pairs with the new LayoutComponent <main> landmark.
<%= midwest_skip_link(href: "#main", label: "Skip to main content") %>FocusTrapComponent
A focus-management wrapper that keeps keyboard focus inside a region (modals, drawers, popovers). Supports active toggling, return_focus to restore the previously focused element on release, and an initial_focus selector.
<%= midwest_focus_trap(active: true, return_focus: true) do %> <!-- modal content — Tab cycles within this region --><% end %>LiveRegionComponent
An ARIA live region for announcing dynamic state changes to screen readers. Choose polite or assertive politeness, and optionally render it visibly. Backed by the shared AriaHelper concern.
<%= midwest_live_region(message: "Your changes have been saved.", politeness: :polite) %>MCP Server — Four New Tools
The MCP server grows from 8 to 12 tools, focused on suggesting, diagnosing, and scaffolding components:
suggest_components— Context-aware suggestions from a code/markup snippet or natural-language description. Combines an intent map (raw HTML tags + synonyms), keyword search, and complementary slot-composition signals, and reports what you already use.diagnose_component— Symptom-driven debugging. Runs nesting, Stimulus-wiring, form-context, constrained-option, and accessibility checks against parsed metadata, ranks likely causes by symptom keywords, and surfaces curated common fixes.get_accessibility_info— ARIA roles, keyboard patterns, focus management, and WCAG success criteria per component. Data-driven viaaccessibility.yml(managed withbin/a11y), with a shared roving-focus pattern covering the interactive component set.generate_preview— Scaffolds a Lookbook preview from a component's parsed metadata: adefaultexample, aplaygroundwith@paramcontrols inferred from options (constant→select, boolean→toggle, integer→number, else text), optional example stubs, and matching sidecar.html.erbtemplates.
What Changed
ARIA patterns — shared AriaHelper concern
A new AriaHelper concern centralizes aria_live_attributes (polite/assertive live regions) and humanized_label (auto aria-label generation). NotificationComponent politeness is now state-aware, and IconComponent labels are fixed for multi-hyphen icon names.
Keyboard navigation — shared roving focus
A shared handleRovingFocusKeydown() helper implements arrow / Home / End / Escape / Tab roving focus. DropdownComponent was refactored to consume it as the reference implementation.
LayoutComponent — <main> landmark & heading helper
LayoutComponent gained an opt-in <main> landmark (display: contents, pairs with midwest_skip_link). A new midwest_heading helper renders level-clamped headings for a correct heading hierarchy, and EmptyStateComponent now accepts heading_level:.
Form::SwitchComponent — change_theme:
Switches can now drive a dark/light theme toggle. Pass change_theme: true to add the dark class to <html> and persist the choice.
What Was Removed
No components, options, or slots were removed in this release. Internally, DropdownComponent's bespoke keyboard-handling code was retired in favor of the shared handleRovingFocusKeydown() helper — a behavior-preserving cleanup with no user-facing change.
Dev Process
MCP accessibility data & tooling
A new AccessibilityIndex loads per-component ARIA, keyboard, focus, and WCAG data from accessibility.yml, maintained through the new bin/a11y CLI. The ComponentParser was substantially expanded to feed the new diagnostic and preview-generation tools.
Component guidance from real projects
component_guidance.yml gained additional guidance distilled from building the Lockbox Connect marketing site and app, improving MCP search and suggestion quality.
CI & quality
- CI workflow updated with an expanded static-checks job.
- RuboCop style offenses in
exe/midwest_mcpfixed to keep static checks green. - Test coverage climbed to 96%.
Expanded test coverage
New and updated test files across components, helpers, MCP tools, and system tests:
MarkdownComponentTest,SocialPreview::{Facebook,Twitter,LinkedIn,Instagram}ComponentTest, andSocialPreviewComponentTest.IntersectionObserverComponentTest(+ system test),OnboardingComponentTestandOnboarding::StepComponentTest(+ system test),SkipLinkComponentTestandFocusTrapComponentTest(+ system tests),LiveRegionComponentTest.EmptyStateComponentTest,Form::SwitchComponentTest,IconComponentTest,LayoutComponentTest,NotificationComponentTestfor accessibility changes.AriaHelperTestandViewHelperTestfor the new helpers.AccessibilityIndexTest,ComponentParserTest, and an expandedServerTest/ToolsTestcovering all twelve MCP tools.