What is the preferred way to have dynamic styles?

With a content security policy defined and upheld, it is no longer possible to use inline style attributes on elements.

I would still like to have some dynamic styling, so thought that it was enough to generate a stylesheet file upon handling certain events. With live_reload watching, I thought I was set:

config :my_app, MyAppWeb.Endpoint,
  ...
  live_reload: [
    notify: [
      live_view: [
        ~r"lib/my_app_web/components/core_components.ex$",
        ~r"lib/my_app_web/(live|components)/.*(ex|heex)$"
      ]
    ],
    patterns: [
      ~r{priv/static/.*(js|css|png|jpeg|jpg|gif)$},
      ...
    ]
  ]

And that works just fine running in development. In production, this doesn’t seem to work.

Another way would be to create a <style nonce={get_csp_nonce()}>...</style> block, but as this has to be in the header, it needs to go into the root.html.heex file, which is not a live layout, and is not reevaluated.

My question is, which is the best way to go? Is there a way to make live_reload work in production without massive performance penalties, or is it better to create an internal style block, and how would it best be updated?

Unless you use a workaround lib that is. See phoenix_live_head | Hex for manipulation and phoenix_live_favicon | Hex to see how one can build a lib on top. Although I think no lib abstraction in needed and Live Head will do.

Depending on the use case one might use CSS vars (custom properties) and only set the variable.

Thank you very much for that pointer @BartOtten ! I’m looking into this library now, trying to find the best way to make it work.

Looks like a fantastic little library, thank you for giving us that!

You’re welcome! Let me know if you have any questions. Forum thread: Phoenix Live Head - HTML Head manipulation for Phoenix Live

1 Like

I do have a question!

I can see, through your documentation, and the server- and client-side code, how you’re mutating attributes. It makes total sense on single-word attributes, but I cannot see how to handle multi-word, or camel-case attributes.

For example, I am trying to change the innerHTML attribute, which—using your documentation and code—I would do in the following way:

document.querySelectorAll('style[id*=dynamic-style-block]')[0].innerHTML = "p{color:red};"

for example, which works in the console. However, in the code, the innerHTML attribute is being ‘translated’ to innerhtml, and it visible in the inspector as an in-line attribute of the element, not the content, as desired.

I am probably not seeing in the code where this is being renamed—apparently I can’t read JS very well—any pointer would be helpful.

P.S. Upon deeper inspection, I can see you’re using the setAttribute() method, where, by default,

The attribute name is automatically converted to all lower-case…
MDN Element: setAttribute() method

so I can probably not use the library as is. It seems that I should propose a diff using the following:

el.textContent += "p{color:red};"

where setting the textContent property is safer than setting innerHTML.

What do you think?

So far Live Head only manipulates inline attributes as this is the first time a use case comes up with a content change :slight_smile:

Are you in a hurry for support or can you continue working on other features while I wrap up the first Release Candidate of Routex?

If you would like to come up with a Pull Request; please also make sure saveState and restoreState are supported by your addition.

I’m happy to work on a prototype fix, I just have one question: I’ve cloned the library to a local folder, and have changed my dependency to the folder, not the release.

I just don’t understand the best way to use it in my application. I don’t understand how to change the source file, such as index.ts, and getting it to have an effect in my consuming application. Sorry for the beginner question…

1 Like

Sorry, I missed this post. Let me get back to this tomorrow.

ps. It’s not a beginner question, I struggle with it every time I pick up the lib to develop something. Has something to do with compilation of assets but I always forget how exactly :slight_smile:

Actually, I worked it out and have fixed my problem perfectly with a quick and dirty solution.

Please give me a few days to make a cleaner and more generic prototype, which I will submit as a PR.

Thanks

1 Like

Hi @BartOtten, I’ve now completed a slightly more generic and clean version of the changes needed to target HTML element textContent properties, in addition to their attributes.

I’ve generated a pull request, please let me know if there’s anything else I can do.

Thanks

P.S. I apologise for the ‘noisier’ than expected diff, it appears that my editor changed quite a bit of formatting automatically, which wasn’t my aim…

Thanks for the PR. Had a quick look and it looks fine at first glance. The security consideration incl documentation of it is greatly appreciated! Will review properly later this week.

The formatting is an oversight of myself. The file was not formatted so your editor did well. So don’t worry, it just made another issue (non formatting) very visible.