Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component or module-level css compiler options #8354

Open
theetrain opened this issue Mar 6, 2023 · 0 comments
Open

Component or module-level css compiler options #8354

theetrain opened this issue Mar 6, 2023 · 0 comments

Comments

@theetrain
Copy link
Contributor

theetrain commented Mar 6, 2023

Describe the problem

While exploring new ways of providing theming flexibility to a component library, I noticed there isn't an easy way to replace or unload a component's styles without adding extra steps for the developer consuming the library (described in 'alternatives' below).

Relates to #6859, #1550.

Describe the proposed solution

I have a few unrefined ideas, and would appreciate any other novel solutions to add to this discussion.

Since the component library comes with styles, I feel the 'happy path' would be importing components onto a page and setting up a single library-provided global.css file for typography and resets. Users who want to supply their own themes would ideally only have to encounter some trivial configuration.

Proposal 1: pass module paths to compiler options

  1. User imports component onto page. By default, it comes with CSS in its <style> and works without extra configuration.
  2. User can 'unload' all component styles by providing a compiler options such as:
const config = {
  css: [
    { 'module-name/ComponentName.svelte': 'none' }, // one component
    { 'library-name', 'none' } // entire library
  ]
}

This has an all-or-nothing drawback; we cannot specify compiler options on a per-instance-of-component basis.

Proposal 2: dynamic <svelte:options>

I thought about using setContext via a wrapper component to pass context to set the css option in <svelte:options>, but I realize <svelte:options> should only accept string literals since it cannot know dynamic settings at compile time:

Here's how dynamic <svelte:options> could have looked

+page.svelte*

<script>
  import { Button, Theme } from 'component-library'
</script>

<Theme overrideCSS>
  <Button>Do the thing</Button>
</Theme>

Button.svelte

<svelte:options css={overrideCSS} />

<script>
  import { getContext } from 'svelte'
  const overrideCSS = getContext('overrideCSS')
</script>

<button class="btn"><slot /></button>

<style>
  .btn { /* ... */ }
</style>

Or perhaps it can be made possible to wrap individual components with <svelte:options> so that a single instance of the component can be changed, while remaining instances use provided styles.

<svelte:options css="none">
  <Button>Button without CSS</Button>
</svelte:options>

<Button>Button with CSS</Button>

Though this would necessarily create a copy of <Button> at build time. Button styles can be overridden with selectors like :where(.btn) so that they do not impact plain usage of <Button>.

Proposal 3: dynamic <style>

Have <style> load conditionally:

<script>
  import { getContext } from 'svelte'
  const overrideCSS = getContext('overrideCSS')
</script>

<button class="btn"><slot /></button>

<style load={overrideCSS}>
  .btn {/* */}
</style>

But this has the drawback of shipping all bytes of CSS whether or not they're being used.

Alternatives considered

  1. <style> is completely unused in every component in the library, and users must either import library-supplied CSS or SCSS, or their own CSS.
  2. Only expose certain styles via CSS variables so that users may override via --style-props. Any custom theming would have to be provided with global CSS selectors that have high specificity.
  3. Using setContext to conditionally import() .css files; but this loads styles onto a page that would impact all instances of a component when only 1 particular instance is meant to be overridden.

Importance

nice to have

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant