Would the Phoenix maintainers - and the community - welcome a PR adding dark mode with selectors consistently to all phx gen templates?

Each time i use phx.gen I end up adding dark mode to it.

I’m offering to add this to the default phx gen templates.

This would

  • use tailwind
  • add new tailwind customization into tailwind.config.js? or wherever you prefer.
  • update core_components and each template
  • put a toggle affordance in the nav
  • default to local preference
  • set toggle state in browser session, overriding preference
  • leave the main phx home page alone
  • happy to also pick up any existing template bugs since i’m in there already - e.g. index page table row hover bg color right column inconsistent height.

I hope you:

  • find this proposal considerate!
  • …clear
  • …worth considering - dark mode feels like a nice default thing to add.

I’ve seen dark mode “how do i” threads in this forum but do not see a proposal to implement. I think LLM agents make this pretty cheap - that’s how i do it each time i start a new project and this feels like it would be similar to one of my one offs but just more extensive and more carefully tested.

I’m open to working with others but happy to just do this myself.

25 Likes

I’m not sure why anyone wouldn’t be happy with this :sweat_smile: I’m not on or close to the Phoenix team but I’m guessing this is one of those non-pressing issues that is merely waiting for someone like you to come along. Just a guess, though! A big plus one from me, and I’m not even a dark mode user.

5 Likes

Hey @cortfritz! @cblavier wanted to do some work on dark mode support in the generators, so maybe you’re able to coordinate the effort :slight_smile:

That being said, I’m paraphrasing a conversation with Chris and José about this topic:

people have complained in the past that core components are daunting to get into, as it’s a huge file we dump into their apps. Adding features will just make it larger and we did our best to keep it small.

I’m a big fan of dark mode, but in the end we’d need to look and see if the changes are fine.

5 Likes

Has there been any talks about adding a flag to not add core components when generating a project like --no-components since we already have --no-gettext and --no-dashboard and other flags to not add things when generating a new phoenix project?

5 Likes

Yes! Andre-Bryan’s point is a great answer to the Chris/José concern.

I’m happy to have my submission include improved flags for control. I’d be happy to ship dark mode behind a flag.

Currently my imagining of dark mode as a feature includes:

  • new dark mode tailwind classes
  • changing all the classes to include the dark mode tailwind classes
  • a javascript hook to capture the toggle, store/retrieve it, default to browser preference
  • ux in the nav in app.html.heex for the toggle control
  • optional: toggle control implemented as a new component in core_components
  • some artistic work styling home page as the really pretty graphic probably also wants a dark mode pallette

so if this is behind a flag, instead of providing new versions of the templates, the Phoenix project templates become more complex to allow for different results depending on flag. Either I’m duplicating templates (not DRY), complicating them by factoring out classes behind flag-sensitive functions (complicated),… or worse: writing a script that changes them if flag is enabled (brittle). I don’t see a solution with nice tradeoffs.

BUT I’ll argue against imagined Chris & José response - in for a penny in for a pound.

Specifically, dark mode feels like table stakes. Since Phoenix is batteries included, might as well keep it to current standards. Higher quality templates (having dark mode) also helps acquisition of discerning engineers. And shipping a default simpler version can happen when it happens.

5 Likes

My suggestion: add the appropriate dark: variants to the existing components, set darkMode: "media" in the Tailwind config file, make any tweaks to generated home page if necessary, and leave everything else as potential follow-up (either via code changes, or even documentation).

This subset above adds a lot of value, and IMO isn’t objectionable in any way: it doesn’t complicate the core components any further (it’s just a few new classes in a sea of existing class soup), and if anyone doesn’t want dark mode it’s as simple as changing one line in the Tailwind config file.

1 Like

@mjrusso I think you are saying

  1. augment the classes to have dark mode capability
  2. modify home page classes, and by common aesthetic standards, probably add alternative dark mode version of the hero graphic
  3. DO NOT create a toggle control or put any ability to toggle in nav
  4. DO make dark mode sensitive to preference via darkMode: “media”

correct?

1 Like

This is a great idea!

I would ask that some research be done to find alternatives to using the tailwind dark: modifier. Using this dark: modifier gets difficult to maintain and creates lots of bloat in the class strings/lists.

For an example alternative, it is possible to define colors in app.css like this:

@layer base {
  :root {
    --text-quiet: 40 42 56;
  }

  .dark {
    --text-quiet: 204 205 207;
  }
}

and then get them into tailwind like this:

  theme: {
    extend: {
      colors: {
        "text-quiet": "rgb(var(--text-quiet))",

and then simply use

<p class="text-text-quiet">

instead of

<p class="text-text-quiet dark:text-text-quiet-dark">

which is (I think) a “usual” way to use the dark: modifier.

Note that this only takes hold if you specify the dark mode somewhere in the root of the HTML, e.g. in the root layout:

<html
  id="my-app-root"
  lang="en"
  class={[if(@color_mode == "dark", do: "dark"), "[scrollbar-gutter:stable]"]}
>

I don’t think my approach is optimal. The necessity of RGB values is quite unpleasant. However, I have found it superior to writing dark: in 1000s of class attributes.

As an extra point, I think it would be better to use custom colors in the tailwind config (or in the css file) than to use the default tailwind colors in the generated files. Tracking down every shadow-cyan-200 and text-red-500 when a style update is being done, that is really painful. Much much nicer to have shadow-subtle-blue and text-error.

I hope this is clear. I am not attached to the outcome. What I have written is meant to be inspirational. If you decide to proceed with dark: in the class strings/lists, then I will still be very grateful. Good luck!

4 Likes

A bit off topic.

If there’s an idea about adding new flags, I’m wondering if this would be something that igniter could help with. Given that @zachdaniel has already thought about igniter tasks for a composable phoenix installer - even done some work already.

5 Likes

Great thinking. I’ll experiment with this.

1 Like

I was thinking about igniter. If you have other ideas about this please post.

I think it will be some time before we get there, if we ever do :slight_smile: At the moment we are exploring if and how we might be able to get Phoenix to adopt igniter, and what the installers could look like in igniter terms. But we haven’t really heard anything from Chris and only barely begun the conversation with José. I would explore other options for building custom view templates for Phoenix for now.

Even if Phoenix adopts igniter, you still would end up needing to maintain a separate set of components/templates, because patching code is much more complex than just swapping out what code is generated.

1 Like

Yes, that’s true but I a minimal effort could already be helpful. If nothing has changed you can replace the components. If things have changed, inform the user and don’t change anything.

Yes, that is what I’m proposing.

I like the other ideas, but I don’t think they are likely to be accepted at this point. The direction lately has been to remove and simplify the core components; they’re just a minimal starting point to hit the ground running.

The other part to consider is that the core components are coupled with the actual code generators, which are also relatively simple. I would personally love more opinionated code generators that really showcase what you can do with LiveView (e.g. wire up pubsub, make everything update in real-time for all connected tabs, etc. etc.), and with more sophisticated and exhaustive components.

So the direction I’d recommend exploring is alternative code generators and integrated components, not necessarily an official part of Phoenix to start (although I think that would be a great medium-term goal), with all the goodness of Igniter etc.

2 Likes

I’d suggest taking a look at tools like Mishka Chelekom, which are already using igniter under the hood to generate components, and have some big updates coming soon :slight_smile:

@shahryarjb ^

5 Likes

Big thanks to dear @zachdaniel ! :raised_hands: All components in the master branch now fully support both dark mode and light mode (and we have base color), with around 80 components ready for you. :muscle: If you want dark mode to be the default, just add the dark mode class to your page’s HTML. Easy peasy! :smile::sparkles:

2 Likes

@slouchpie one of the lifts implied by your approach is to find and replace any class declarations that only use default tailwind to use a a new phoenix custom class which implements dark mode. I can imagine that the maintainers feeling pro or con for that abstraction. It’s a bit more work for me but not impossible. The abstraction itself - designing a coherent and exhaustive set of custom classes and factoring them in to every template - is more work but I’m up for it if that’s a good way to go.

Alt: go the custom generator route also being discussed in this thread.

I am currently working on a custom opinionated generator GitHub - Zurga/punkix: Personal Phoenix generators. I want it to have support for associations in generators, pubsub in liveviews and some other stuff I will write down.

It is still a work in progress, because adding support for associations in LiveViews and subscribing to PubSub takes some work to get right. Currently I would like to experiment with EctoWatch and a GenServer that routes updates to the LiveViews.

One of the hurdles I had to take is the fact that you sometimes want to override some of the default functionality that is used by the Phoenix generators. You could fork Phoenix, but then you have to maintain a fork. Punkix patches some of the Phoenix generator functions by either wrapping them or replacing them entirely. To do this, the modules are decompiled and then modified, namespaced seperately and reloaded in the BEAM. This part of Punkix is standalone and might aid others who want to go this route.

1 Like

As Steffen said @cblavier has been exploring what dark mode would look like code wise and initial results are promising. We told Christian we’d need to see code side by side to see if it’s overwhelming or not. I’m camp dark-mode-everything fwiw, so we’ll see!

10 Likes

Wondering if it’s better to do the CSS variable trick for dark mode or to instead specify with the dark: variant everywhere.

Would be interested to see which is easier to maintain/set up

The CSS variable trick looks nice, but it’s hard to say how one would “migrate” to dark mode if they already have colors specified everywhere with the defaults.

1 Like