DEV Community

Serhii Jun
Serhii Jun

Posted on

Not-so-ugly styles code in your Rails app

Let's say, u already normally human and didn't use tailwindcss for your Rails app. Well, I just want to show you how I uses a feature from ruby-3.2 introduced by @zverok. It names Data and I use it together with ViewComponent and Rux to have a little less ugly code.

Gemfile:

group :development, :test do ... gem 'view_component', '~> 2.82' gem 'rux-rails', '~> 1.2', '>= 1.2.2' gem 'birdel', '~> 3.1' end 
Enter fullscreen mode Exit fullscreen mode
  1. Generate new component by ViewComponent or by Birdel
$ birdel gcom Ui::Mix::BarComponent # app/ # ├─ components/ # │ ├─ ui/ # │ │ ├─ mix/ # │ │ │ ├─ bar_component/ # │ │ │ │ ├─ bar_component.rb # │ │ │ │ ├─ bar_component.js # │ │ │ │ ├─ bar_component.css # │ │ │ │ ├─ bar_component.html.erb # │ │ │ │ ├─ bar_component_controller.js # │ │ │ │ └─ bar_component_actor.js 
Enter fullscreen mode Exit fullscreen mode
  1. remove your bar_component.html.erb file

  2. Write your styles into bar_component.css

  3. Rename bar_component.rb file to bar_component.rux

#app/components/ui/mix/bar_component/bar_component.rux class Ui::Mix::BarComponent::BarComponent < ViewComponent::Base Styles = Data.define( :nav_bar, :nav_item, :btn, :btn_active, :nav_item__logo ) attr_reader :styles def initialize() end def styles @styles ||= Styles.new( nav_bar: 'nav-bar', nav_item: 'nav-item', btn: 'nav-item-btn', btn_active: 'nav-item-btn--active', nav_item__logo: 'nav-item-logo' ) end def call <div class={css_class} data-controller={css_class}> <div class={styles.nav_bar}> <div class="#{styles.nav_item} #{styles.nav_item__logo}"> </div> <div class={styles.nav_item}> <div class={styles.btn} data-action="click->#{css_class}#handleLeftBtn">Left</div> <div class="#{styles.btn} #{styles.btn_active}">Center</div> <div class={styles.btn}>Right</div> </div> <div class={styles.nav_item}> </div> </div> </div> end def css_class @css_class ||= "ui--mix--blabla..." end end 
Enter fullscreen mode Exit fullscreen mode

Explanation:

In this part we define a custom Data class named Styles with fields, which will be used as the names of classes from our style file:

 Styles = Data.define( :nav_bar, :nav_item, :btn, :btn_active, :nav_item__logo ) 
Enter fullscreen mode Exit fullscreen mode

And here we just set a value for each field of our Styles data object:

 def styles @styles ||= Styles.new( nav_bar: 'nav-bar', nav_item: 'nav-item', btn: 'nav-item-btn', btn_active: 'nav-item-btn--active', nav_item__logo: 'nav-item-logo' ) end 
Enter fullscreen mode Exit fullscreen mode

Great now we can use that @styles object inside #call method which allows us to write the same to JSX-styled syntax code. Like:

<div class={styles.nav_item}> 
Enter fullscreen mode Exit fullscreen mode

Example rendered HTML:

<div class="nav-bar"> <div class="nav-item nav-item-logo"> </div> <div class="nav-item"> <div class="nav-item-btn" data_action="click->ui--mix--bar-component#handleLeftBtn"> Left </div> <div class="nav-item-btn nav-item-btn--active"> Center </div> <div class="nav-item-btn"> Right </div> </div> <div class="nav-item"> </div> </div> 
Enter fullscreen mode Exit fullscreen mode

Btw, Birdel (https://github.com/serhiijun/birdel) is my microframework which is not ready yet and you can help me by contributing. It's revolutionized tool for rails assets management and WebSocket components rendering which will replace sucks rails-turbo.

Top comments (0)