Create a String to Color Helper with Ruby (and Rails)
Tags: ruby, rails, webdev
Published: 2024-07-15 08:00:00

This article was originally published on [Rails Designer](https://railsdesigner.com/uby-string-to-colors/).

---

In the [latest version (v1) of Rails Designer](https://railsdesigner/com/) I added a [Chat Messages Component](https://railsdesigner.com/components/chats/).

For one of the provided variants I wanted to have a [different background- and text-color based on the user's name](https://railsdesigner.com/components/chats/#group-chat). I like this kind of “random” customizations to UI components, as it gives an otherwise monotone UI layout some sparkle. In the context of chat messages it works well too differentiate between the different messages from users.

I used a similar technique for the [AvatarComponent](https://railsdesigner.com/components/avatars/). Here, when no profile picture is available (`attached`), it calculates the color for the user name's initial.

I typically calculate these colors at runtime, but I can imagine, when your app grows, to store them alongside the user in some sort of [preferences model](https://railsdesigner.com/simple-preferences/).

> [Rails Designer](https://railsdesigner.com/) is a professionally designed UI components library for Rails. Built with ViewComponent. Designed with Tailwind CSS. Enhanced with Hotwire. Build beautiful, faster.

For the example of the chat messages I wanted to pick one of [Tailwind CSS' colors](https://tailwindcss.com/docs/customizing-colors). This is because the the background- and text color is set as follows:

```ruby
# …

def initialize(name:)
  @name = name
  @color = string_to_color(name)
end

def chat_css = class_names("px-3 py-1 rounded", states[@color])

def states
  {
    red: "bg-red-100 text-red-800",
    blue: "bg-blue-100 text-blue-800"
    # …
  }
end
```

(example simplified for demonstration purposes)

So how does the `string_to_color` helper look like? It's pretty straight-forward. Let's see:

```ruby
# app/helpers/string_to_color.rb
module StringToColorHelper
  def string_to_color(string, colors: TAILWIND_COLORS)
    hash_value = string.downcase.each_char.sum(&:ord)
    index = hash_value % colors.length

    colors[index]
  end

  private

  TAILWIND_COLORS = %w[
    slate gray zinc neutral stone
    red orange amber yellow lime green emerald teal cyan sky blue indigo violet purple fuchsia pink rose
  ].freeze
end
```

It calculates a hash value (`hash_value`) from the given string by converting each character to its ASCII value. So given a string of `Example` will output:

```ruby
"Example".downcase.each_char # ['e', 'x', 'a', 'm', 'p', 'l', 'e']
```

Then, based on the ASCII characters, the sum is returned.

```ruby
"Example".downcase.each_char.sum(&:ord)
# `&:ord` → [101, 120, 97, 109, 112, 108, 101]
# `sum()` → 748
```

This sum is then used to select an index from the `colors` array. Using the modulus of the `hash_value` (`hash_value % colors.length`) with the length of the colors array ensures the index is always within the bounds of the array.

By default this uses the `TAILWIND_COLORS` constant, thus always returning `slate`, `gray`, `red`, etc. But you can also pass another array with hexadecimal colors (directly) to the method. Like this: `string_to_color("Example", colors: ["#3498DB", "#2ECC71", "#F1C40F"])`.

V1 of Rails Designer comes with this new helper out of the box. [Check out the docs for more details](https://railsdesigner.com/docs/view-helpers/#string-to-color).