
Improving Phlex Ergonomics... or trying to (in Rails)
Reading time: 10 minutes
Currently, Phlex has a feature called Kits.
Kits make instantiating components easier:
# beforediv do render Components::Card.new(variant: "warning")end
# afterdiv do Components::Card(variant: "warning")end
While it is an upgrade, it is limited in that it only works within Phlex components, and I’d prefer if it looked like using helpers. Let’s improve this.
Using shebang helpers
class PhlexHelper < Phlex::HTML def card!(*, **, &) render(Components::Card.new(*, **), &) endend
class Components::Base < Phlex::HTML ... include PhlexHelper ...end
This is great because it works in ERB as well.
The shebang is also great because it avoid collisions with native HTML elements.
I saw some people using prefixes instead (like x_card
) but I don’t like that.
Macro’ing these helpers
module PhlexHelper def self.define_component(name, to: name) define_method("#{name.to_s.parameterize.underscore}!") do |*args, **kwargs, &block| mod = Components.const_get(to.to_s.classify) render(mod.new(*args, **kwargs), &block) end end
define_component "admin/form" # This defines admin_form! referencing to Components::Admin::Form define_component "form", to: "form/form" # This defines form! referencing Components::Form::Formend
Keep Phlex code in views/components
I prefer to keep all html content within app/views
I don’t like having to switch between app/views
and app/components
module Components extend Phlex::Kitend
Rails.autoloaders.main.push_dir( Rails.root.join("app/views/components"), namespace: Components)
(I don’t do phlex views, nothing against it, just that it collides with this style of keeping components within views/)
Looks like idiomatic ruby code
RubyUI uses this:
Accordion do AccordionItem do AccordionTrigger do p(class: "font-medium") { "What is PhlexUI?" } AccordionIcon() end endend
But with this style, it looks like this
accordion! do accordion_item! do accordion_trigger! do p(class: "font-medium") { "What is PhlexUI?" } accordion_icon! end endend# looks good to me!