sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.19k stars 4.09k forks source link

JS access to --style-props #7868

Open theetrain opened 1 year ago

theetrain commented 1 year ago

Describe the problem

Sometimes I want to take a passed in --style-prop and use that value to compute a new value. --style-props currently can be used to override values set in a component's <style>, and the only way to override them (that I know of) is via window.getComputedStyle() that cannot run during Serverside Rendering.

Example:

<!-- Page.svelte -->
<Component --text-color="red">Some text</Component>

<!-- Component.svelte -->
<script>
const createHighContrastBG = () => { /* ... */ }
</script>
<div 
  style="color: var(--text-color);
  background-color: {createHighContrastBG(--text-color)}"> <!-- not possible -->
  <slot />
</div>

Describe the proposed solution

A way to access --style-props via JS, such as $$styleProps or within $$restProps. This way, CSS variables can be exposed via --style-props, and can be potentially SSR-friendly.

<!-- Page.svelte -->
<Component --text-color="red">Some text</Component>

<!-- Component.svelte -->
<script>
const createHighContrastBG = () => { /* ... */ }
</script>
<div 
  style="color: var(--text-color);
+ background-color: {createHighContrastBG($$styleProps['--text-color'])}">
  <slot />
</div>

Alternatives considered

  1. Here's a workaround REPL using window.getComputedStyle(): https://svelte.dev/repl/7b566ad5f79a403291106ae3bf048057?version=3.50.1
  2. Use regular props and define styles inline. For the above example, that could mean setting a textColor prop.
  3. Concede that --style-props is meant to expose overridable component CSS variables, to be kept simple and SSR-friendly. The concept of 'computed style props' may be regarded as a 'second set of props' and I can see how that may conflate the responsibilities of props and --style-props leading to potentially confusing component APIs in UI libraries.

Thanks for having this discussion.

Importance

nice to have

Mlocik97 commented 1 year ago

 and the only way to override them (that I know of) is via window.getComputedStyle() that cannot run during Serverside Rendering.

Not true at all... see:

https://svelte.dev/repl/8123d474edb04f198c3b83363716a709?version=3.23.2 or https://svelte.dev/repl/6ee34efa8b57411faf6bccb24e3f95a9?version=3.37.0

theetrain commented 1 year ago

@Mlocik97 thanks for taking the time to share those helpful examples. They're similar to my Alternative (2) since they utilize JS variables to define colour (bound to color <input />s), and could theoretically use props as well. However, I'm not sure if it's possible (or appropriate) to be able to compute styles from --style-props.

The experience I'm looking for is the ability to consume a component in code (not client-side), pass in a style prop, and have that style prop be consumed for a "computed" style. Take for example this High Contrast Button demo: https://svelte.dev/repl/8615f71b48304f2dba94b23edbe758ae?version=3.50.1

In here I want to pass --color to the <Button /> component in order to compute the variable --bgColor, but as far as I know this doesn't seem possible with --style-props since those aren't directly accessible in JS unless I use window.getComputedStyle(). It's achievable with regular Svelte props as mentioned in Alternative (2).

Does it seem useful to be able to compute CSS variables based on other CSS variables defined via --style-props?