Philosophy
Why Wabi works the way it does, and where it fits in the Rails ecosystem.
You own the code
Wabi components are not imported from a node_modules-equivalent. When you run `bin/rails g wabi:add button`, the Phlex source is COPIED into `app/components/ui/button.rb`. You can edit it, refactor it, fork it. There is no upstream API for it to drift away from, because the upstream is now you.
This trade-off is deliberate. The cost is no automatic component upgrades when Wabi ships v0.3 — your existing components don't move. The benefit is that customization is the default mode rather than an escape hatch.
Phlex-native, not ERB-wrapped
Phlex components are Ruby classes. Composition is method dispatch. Variants are class-method DSLs. Inheritance is real inheritance. This trades a bit of newcomer friction for a model that scales like the rest of your Rails app.
Accessible by default, not retrofitted
Every interactive component wires through @zag-js state machines, which carry WAI-ARIA roles, keyboard semantics, and focus management baked in. Overlays toggle the inert attribute when closed so they stay out of tab order and the accessibility tree. The goal is WCAG-AA out of the box for every component shipping.
Brand-neutral
Wabi ships 8 palettes with carefully chosen accent colors and neutral grayscales. No single one is the "Wabi look" — pick the one closest to your brand, or edit the HSL values directly. The visual identity is the user's, not ours.
Hotwire and Turbo-friendly
Stimulus controllers wrap the Zag state machines so they survive Turbo navigation. The Toast component ships a `turbo_stream.wabi_toast` action helper so server-side code can spawn notifications without round-tripping the page. Wabi is opinionated about working with Rails, not around it.