A Page screen shot of the Color Option form being developed in the following tutorial

Color Picker with Ruby on Rails 6, Stimulus and Webpacker

April 12, 2020 RSS Feed Only Files Quick View

Demo Application - Hosted on a Free dyno. (May take 10-20 seconds to wake up)

Github - Git repo for the hosted application.

Tools

  • Ruby on Rails 6.0.2.2 - Ruby Web Framework
  • StimulusJS - A minimal Javascript framework developed by Basecamp.
  • Webpacker - Rails gem for using Webpack to bundle assets including Javascript modules.
  • Pickr - Color Picker Javascript library.

Set Up

This tutorial assumes that you have a Rails application with webpacker and stimulus installed (along with some familiarity using each).

If you are using Rails >= 6.0 version, you can generate the application with the following command.

rails new sample_app --webpacker=stimulus

The demo model we working with is the ColorOption.

ColorOption(
  id: integer,
  font_color: string,
  background_color: string,
  created_at: datetime,
  updated_at: datetime
)

As you can see above the model has two string columns

  • font_color: string
  • background_color: string

These will be updated by the Color Picker. The columns can currently be updated using a regular rails form.

app/views/color_options/_form.html.haml

= form_with(model: local_assigns[:model], local: true) do |f|
  .field
    = f.text_field :font_color
    = f.label :font_color
  .field
    = f.text_field :background_color
    = f.label :background_color
  .field
    = f.submit

Pretty standard stuff, now lets get the Color Picker library installed.

Install with Yarn & Webpacker

Add the Pickr library using yarn

Command Line

yarn add @simonwep/pickr

Afterwords, create a css file to load the module’s styles.

app/javascript/stylesheets/color_picker.css

/*Change 'classic' to which ever theme you are using from Pickr*/
@import '@simonwep/pickr/dist/themes/classic.min.css';

/*Custom form field style*/
form .field .pickr {
  display: inline-block;
}

NOTE: If you do not use a css style path such as app/javascripts/stylesheets/ in your build, you can load the the Pickr library styles in the packs file.

app/javascripts/packs/application.js

import '@simonwep/pickr/dist/themes/classic.min.css';

Stimulus Integration

app/javascript/controllers/color_picker_controller.js

import { Controller } from "stimulus";
import Pickr from "@simonwep/pickr";
import "../stylesheets/color_picker.css";

export default class extends Controller {
  static targets = ["picker", "input"]

  initialize() {
    this.initPicker();
  }

  initPicker() {
    this.picker = Pickr.create({
      el: this.pickerTarget,
      theme: 'classic',
      default: this.inputTarget.value,

      components: {
        preview: true,
        opacity: true,
        hue: true,

        interaction: {
          hex: true,
          rgba: true,
          hsla: false,
          hsva: false,
          cmyk: false,
          input: true,
          clear: false,
          save: true,
        },
      },
    });

    this.picker.on('save', (color, _instance) => {
      this.inputTarget.value = color.toHEXA().toString();

      this.picker.hide();
    });
  }
}

We load the Pickr class from the node module at the top of the stimulus controller file along with the stylesheet.

NOTE: Do NOT load the stylesheet if already imported in app/javascript/packs/application.js

import Pickr from "@simonwep/pickr";
import "../stylesheets/color_picker.css";

We have two stimulus targets.

static targets = ["picker", "input"]
  • this.pickerTarget

    This is the HTML element we will be using to initialize the Picker class with. It will turn the element into a Picker button.

  • this.inputTarget

    This Is the HTML form input we will fill after a color has been selected/picked.

We use the initialize() stimulus lifecycle function:

initialize() {
  this.initPicker();
}

To call this.initPicker() which contains all of the logic to intialize the Pickr component.

We set an instance of the Pickr class to this.picker in order to use in the callback.

initPicker() {
  this.picker = Pickr.create(...)

  //ect...
}

The create settings were provided by the Picker README with the exception of setting el and default.

el: this.pickerTarget,
default: this.inputTarget.value,

This uses the controller’s this.pickerTarget to set the picker element, and the value of this.inputTarget to initialize the Picker with.

We then use the on save Pickr callback in order to:

  • Set the input field’s value
  • Hide the widget

After a user has clicked “Save” on the Color Picker.

this.picker.on("save", (color, _instance) => {
  this.inputTarget.value = color.toHEXA().toString();

  this.picker.hide();
});

Final Touches

Now all we have to do is update our form partial to utilize the color-picker controller.

app/views/color_options/_form.html.haml

= form_with(model: local_assigns[:model], local: true) do |f|

  .field{ data: { controller: "color-picker" } }
    = f.text_field :font_color, data: { target: "color-picker.input" }
    %div{ data: { target: "color-picker.picker" } }
    = f.label :font_color

  .field{ data: { controller: "color-picker" } }
    = f.text_field :background_color, data: { target: "color-picker.input" }
    %div{ data: { target: "color-picker.picker" } }
    = f.label :background_color

  .field
    = f.submit