You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
description: You can edit the color scheme for this website right in this blog post. I‘ll show you how I did it so you can add custom color schemes to your Rails application.
6
-
published: '2024-07-10'
5
+
description: This post embeds a demo of a custom color scheme previewer while highlighting the benefits of Rails, Hotwire, and CSS variables. You can edit the color scheme of this website right in content of this blog post.
6
+
summary: This post embeds a demo of a custom color scheme previewer while highlighting the benefits of Rails, Hotwire, and CSS variables. You can edit the color scheme of this website right in content of this blog post.
In this post, I will describe how to enable users to customize the color scheme of your Rails application. We’re going to accomplish this with [Ruby on Rails](https://edgeguides.rubyonrails.org/), [Hotwire](https://hotwired.dev/), and [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).
15
-
16
-
But before I tell you how to add customizable colors to your Rails app, I want show you first.
17
-
18
-
Below, you can edit the color scheme of this site. You can preview different color schemes right here on this page. You can also save your choice browse the site with your new colors.
15
+
This blog post lets you edit the color scheme of this site.
19
16
20
17
Give it a try.
21
18
@@ -24,152 +21,133 @@ Give it a try.
24
21
JavaScript not enabled? Go to the <%= link_to "color scheme demo", settings_color_scheme_path(custom_color_scheme_params) %>. Then come back when you’re done.
25
22
</noscript>
26
23
27
-
Pretty cool, huh?
28
-
29
-
## Key ingredients
24
+
---
30
25
31
-
The key ingredients to making this work the way it does:
26
+
## How it works
32
27
33
-
- CSS Variables
34
-
- `ActiveRecord` to store curated color schemes
35
-
- Rails `session` to store the user selection
36
-
- Rails `Turbo` for a single-page application experience
28
+
Pretty cool, huh? Here are the key ingredients:
37
29
38
-
## Theme with CSS Variables
30
+
- [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties): Also known as CSS custom properties
31
+
- [SQLite](https://www.sqlite.org/): A `color_schemes` table to store curated color schemes
32
+
- [Cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies): A session cookie to store your saved color scheme selection
33
+
- [Hotwire](https://hotwired.dev/): Server-rendered HTML and a single-page app experience powered by Rails, [Turbo Drive](https://turbo.hotwired.dev/handbook/introduction#turbo-drive%3A-navigate-within-a-persistent-process), and [Turbo Frames](https://turbo.hotwired.dev/handbook/introduction#turbo-frames%3A-decompose-complex-pages)
39
34
40
-
A key piece of making a customizable color scheme is using [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). CSS variables make it easy to change repeated CSS in a lot of places. They can also be overridden.
35
+
I started with the premise of using a monochromatic color scheme based on the 11 color scale Tailwind uses for each of [its default color sets](https://tailwindcss.com/docs/customizing-colors). The curated options are all generated from [uicolors.app](https://uicolors.app/create).
41
36
42
-
You can set a CSS variable with double dashes, `--`:
37
+
Each color scheme is a row in the `color_schemes` table, with a name and CSS hex code values for each of the eleven weights.
Setting a variable doesn't do anything yet. To make use of a CSS variable, call `var()` in a relevant property:
53
+
CSS variables make it easy to change repeated CSS in a lot of places. You can set a CSS variable with double dashes, `--`. The CSS variable can be accessed using the `var()` expression. CSS variables can be overridden and can be defined in terms of other variables.
51
54
52
-
```css:{"show_header": false}
53
-
a {
54
-
color: var(--my-link-color);
55
-
}
56
-
```
57
-
58
-
CSS variables are available within the scope they are declared. To make a CSS variable available everywhere in your CSS, declare it in the pseudo-class `:root`:
55
+
Here’s a simplified a view of how I used CSS variables to define the main background color of the `<body>` element.
Now we can use `--my-link-color` with any selector:
67
-
68
-
```css:{"show_header": false}
69
-
a,
70
-
.button {
71
-
color: var(--my-link-color);
65
+
body {
66
+
background-color: var(--theme-color-50);
72
67
}
73
68
```
74
69
75
-
CSS variables can be defined in terms of others.
70
+
Even though Joy of Rails does not use Tailwind, this approach is consistent with [the Tailwind docs for using CSS variables to customize Tailwind colors](https://tailwindcss.com/docs/customizing-colors#using-css-variables).
76
71
77
-
```css:{"show_header": false}
78
-
:root {
79
-
--theme-link-color: var(--my-link-color);
80
-
}
81
-
```
72
+
When you click the "Save" button, the application stores the `id` of the chosen color scheme in your Rails session:
82
73
83
-
The `var()` expression allows for declaring a fallback. In the example below, `--theme-link-color` will be set to the value of `--my-link-color` if defined, otherwise it will be the given `rgb()` value.
This will work even when `--my-link-color` is defined _after_ `--theme-link-color` or even changed after, such as via a JavaScript interaction like through the color scheme form above.
92
-
93
-
Together, these features help make CSS variables an ideal choice for setting up customizable themes.
78
+
When the page is rendered, the application checks for the presence of the session data to query for the desired color scheme:
94
79
95
-
## Putting it together with Joy
96
-
97
-
Want to know how [Joy of Rails](/) defines its theme?
98
-
99
-
It starts with the color palette. Here are the colors for the site’s theme, defined as CSS variables on `:root`. They are all shades of blue using the same weight pattern as you’ll find in [Tailwind colors](https://tailwindcss.com/docs/customizing-colors).
These variables aren’t used directly in any CSS, for the most part. They are used to define the general site theme variables, which I call `--joy-color-<weight>`.
I can override the `:root` properties within certain scopes, such as when I want to change this up for the Dark Mode theme while mixing-and-matching with other properties, like for general grays and whites.
Remember the `--my-color` CSS variables? When you select a color scheme to preview or save, the application inserts the predefined weights as inline styles when the page is rendered. Because of the way the theme colors are defined above, `--my-color` weights take preference over the default when they are defined.
This works for Tailwind too! The approach used here is consistent with the Tailwind docs section on [customizing colors using CSS variables](https://tailwindcss.com/docs/customizing-colors#using-css-variables).
There's a lot more to CSS variables than what I’ve described here. Check out [MDN's introduction to CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) to go deeper.
86
+
The color scheme CSS variables can be written directly into a style tag
Building your own color scheme(s) in CSS is beyond the scope of this article but I suggest you start by picking some colors. I recommend [uicolors.app](https://uicolors.app) for Tailwind-friendly color palettes. [ColorHunt](https://colorhunt.co/) is a great choice for broad appeal.
99
+
Most of the time-consuming work required to assemble this post was in researching the color palettes and building the site theme with various background and text colors defined in CSS variables.
128
100
129
-
## ActiveRecord bits
101
+
## Progressively enhanced
130
102
131
-
Each color scheme is backed by an ActiveRecord model, `ColorScheme`, which has a name and eleven columns to represent each of the color weights:
103
+
Did you notice how the color choice updated automatically in place? At least, it should have for visitors that have JavaScript enabled.
<em>I can see you don’t have JavaScript enabled! That’s okay! The color schemes preview should have at still worked, which might not have been true had I used a JavaScript framework that relies on client-side rendering.</em>
108
+
</p>
109
+
</noscript>
134
110
135
-
The `ColorScheme` model provides a method for accessing the color weights as `ColorConversion::Color` objects.
111
+
One of the things I love about Rails and Hotwire is that it’s possible to adopt **progressive enhancement**.
> Progressive enhancement is a design philosophy that provides a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience only to users of the most modern browsers that can run all the required code.
In this case, visitors who don’t have JavaScript enabled would see a link to the the <%= link_to "color schemes settings page", settings_color_scheme_path %>. That page has most of the functionality you see here.
140
118
141
-
Did you notice how the color choice updated automatically? At least, it should have; I’m assuming you have JavaScript enabled.
119
+
This design is made possible by the fact that the color scheme preview HTML is all rendered on the server with Ruby on Rails. With JavaScript enabled, Turbo JavaScript "upgrades" the default browser form submissions and link clicks to AJAX requests and use the HTML response to replace the parts of the page in place. Without JavaScript, visitors will still get the desired results after a full page navigation and/or redirects.
142
120
143
-
If you don’t have JavaScript enabled, you would still be able to navigate to the <%= link_to "color scheme settings page", settings_color_scheme_path %> to edit your color scheme. One thing I love about building interactive components with Rails is you can choose to adopt [progressive enhancement](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement)—that is to say: make the site work for "as many users as possible" while providing improvements for fully enabled devices and modern browsers—something I strive for with [Joy of Rails](/).
121
+
Progressive enhancement hasn’t necessarily been a hot topic alongside the popular JavaScript frameworks that rely on client-side rendering. It’s nice to see that most of what you see on these pages is static content and shouldn’t require a lot of code running in your browser to view.
144
122
145
-
When the article renders, a turbo frame tag is inserted that points to the <%= link_to "color scheme settings page", settings_color_scheme_path %>. It looks something like this:
Turbo Rails will recognize the `<turbo-frame>` tag and make an XHR request to the Rails backend for the given `src`, in this case, `'/settings/color_scheme'`.
135
+
This isn’t to say I don’t like writing JavaScript or that I don’t think you should use JavaScript. I’m not here to tell you that you shouldn’t use React. Or Vue, Svelte, Solid, or Angular. Personally, I think JavaScript and the popular JavaScript frameworks are great. I recognize why and how they have become so popular.
158
136
159
-
This corresponds to the `show` action in Joy of Rails’ `ColorSchemesController`:
137
+
I’m also not here to tell you that Rails with Hotwire is objectively better than any of these JavaScript frameworks or similar options.
But—and this is the important point—I didn’t _need_ any client-side rendering or JavaScript component library to make this work. It _is_ possible to build a single-page application experience in Rails. It’s not always necessary to build a single-page application in JavaScript.
162
140
163
-
When you visit that page directly in your browser, you get a full page experience at that url.
141
+
For a solo developer with a busy home life and a full-time job, saving time and energy for other important tasks, like writing, with a language and framework I love; this makes all the difference.
164
142
165
-
To make this also work with a turbo frame, we make a few small adjustments.
143
+
---
166
144
167
-
If the response contains a corresponding turbo-frame that with a matching ID, in this case, "color-scheme-form", then Turbo Rails will insert the HTML into the document at the matching ID.
145
+
Would you like to see an in-depth tutorial on how to build the custom colorscheme functionality? Did you find a bug or do you have questions about the content? Please [send me an email](mailto:[email protected]). You can also connect with me on [Twitter](https://twitter.com/rossta), [Github](https://github.com/rossta), [Mastodon](https://ruby.social/@rossta), and [Linkedin](https://www.linkedin.com/in/rosskaffenberger).
168
146
169
-
```rb
147
+
Curious to peek behind the curtain and get a glimpse of the magic? [Joy of Rails is open source on Github](https://github.com/joyofrails/joyofrails.com).
170
148
171
-
```
149
+
If I’ve captured your interest and you’d like to learn more, please <%= link_to "subscribe", "#newsletter-signup" %> to hear more from me and get notified of new articles by email.
172
150
173
-
Subsequent requests triggered by interactions in the turbo frame, such as link clicks and form submits, will also be scoped to the turbo frame as well.
151
+
I hope I was able to demonstrate a tiny peek into what’s possible with Rails. I hope you enjoyed it.
174
152
175
-

153
+
')
0 commit comments