carbon-design-system / carbon-components-svelte

Svelte implementation of the Carbon Design System
https://svelte.carbondesignsystem.com
Apache License 2.0
2.68k stars 261 forks source link

How to override styles on components? #347

Closed TKTheTechie closed 3 years ago

TKTheTechie commented 3 years ago

Hello,

Apologies for posting this as an issue but its unclear to me from the docs/examples on how to modify the default styles of the various svelte components. For example, if I want to make the primary Button component green how do I accomplish this? Likewise, I'm looking for guidance on setting spacings, margins for the various svelte components or the grids

Thanks

metonym commented 3 years ago

@TKTheTechie What is your set-up? Rollup/webpack etc.

Fortunately, Carbon is highly customizable. There are two main approaches to customizing the theme, including colors, spacing, typography and other tokens.

1) Build time using SCSS

Make sure you have the following development dependencies installed:

Set up svelte-preprocess like so:

      preprocess: require("svelte-preprocess")({
        postcss: {
          plugins: [
            require("autoprefixer")({
              overrideBrowserslist: ["last 1 version", "ie >= 11"],
            }),
          ],
        },
      }),

With svelte-preprocess, you should be able to write SCSS in your svelte style blocks.

Refer to the list of tokens that can be customized.

<!-- App.svelte -->
<style lang="scss" global>
  @import "carbon-components/scss/globals/scss/_theme.scss";

  $carbon--theme: map-merge(
    $carbon--theme--g10,
    (
      interactive-01: green
    )
  );
  @include carbon--theme();

  $feature-flags: (
    ui-shell: true,
    grid-columns-16: true
  );
  $css--font-face: true;
  $css--plex: true;

  @import "carbon-components/scss/globals/scss/css--font-face";
  @import "carbon-components/scss/globals/grid/grid";
  @import "carbon-components/scss/globals/scss/styles.scss";
</style>

Sample result:

Screen Shot 2020-10-19 at 10 25 37 AM

2) Run time using CSS variables

This requires the pre-compiled CSS stylesheet that contains all themes. The import path is "carbon-component-svelte/css/all.css".

Then, you can programmatically update the CSS variables using JavaScript:

document.documentElement.style.setProperty("--cds-interactive-01", "green");
TKTheTechie commented 3 years ago

Excellent thank you for the quick reply. I'm trying to do override this locally in a single file using scss.. I added the plugins and the scss block but I'm getting the following error:

[!] (plugin svelte)Error: File to import not found or unreadable: carbon-components/scss/globals/scss/_theme.scss.

Here is the relevant section of my rollup.config.js:

plugins: [
        svelte({
            // enable run-time checks when not in production
            dev: !production,
            // we'll extract any component CSS out into
            // a separate file - better for performance
            css: css => {
                css.write('bundle.css');
            },
            preprocess: sveltePreprocess({
                sourceMap: !production,
                postcss: {
                    plugins: [
                        require("autoprefixer")({
                          overrideBrowserslist: ["last 1 version", "ie >= 11"],
                        }),
                      ],
                },
            },

            ),
        }),
metonym commented 3 years ago

@TKTheTechie Do you have carbon-components installed?

TKTheTechie commented 3 years ago

Thank you again. Sorry yes - my fault, I didn't realize I had to seperately install the carbon-components plugin.

I do see that I can use scss to affect a global style but how do I affect a local style with the component. If I use the same code snippet and remove the global tag, the change does not affect my svelte component.

metonym commented 3 years ago

@TKTheTechie Great question.

The carbon-components SCSS must be global in order for it to style any of the components. I'd recommend having this SCSS be at the top-level of the app (i.e. App.svelte) because any changes to it will cause the SCSS to recompile (which may take several seconds).

However, you should still be able to use local, scoped component styles by omitting the "global" style block attribute.

Example:

<!-- App.svelte -->
<style lang="scss" global>
  @import "carbon-components/scss/globals/scss/_theme.scss";
  /* ... global SCSS */
</style>
<!-- MyComponent.svelte -->
<style>
  h1 { color: red; }
</style>

<h1>Heading 1</h1>
TKTheTechie commented 3 years ago

I see - the following does work too... just wondering if its the right thing to do and if there are any caveats that you may see.

<Button icon={Plug16} kind="secondary" on:click={addNode} style="background-color:green">Connect All</Button>

Also, can you provide me some guidance on spacing of components. Say I wanted to align my button in the fluid form to the right. The way I've currently done this is as follows...

<FluidForm>
    <Grid>
    <Row>
    <Column>
    <div class="right-content"><Button icon={Misuse16} kind="tertiary" size="small" style="border:none" on:click={close}></Button></div>
    </Column>
    </Row>
...
<Style>
 .right-content {
        display: flex;
        justify-content: flex-end;
    }
</Style>

Is there a more official way of going about this?

metonym commented 3 years ago

Your approach is correct – I also use a combination of classes and inline styles for controlling the layout.

I suppose one caveat for inline styles is vendor prefixing (i.e. transform, -webkit-transform etc.)

TKTheTechie commented 3 years ago

Excellent thank you!

nathanblair commented 3 years ago

@metonym Is this approach still the intended approach to customize carbon theming?

I wondered what the difference, if any, I would see if I went with this approach over either @importing the scss source files in this repo, like @import "carbon-components-svelte/css/white"; @import "carbon-components-svelte/css/g100";? It looked like there were more imports going on in the scss source files in this repo so I thought more work would be necessary to get it working in a scope like the App.svelte style section.

Additionally, and this may be out of scope of this issue, but if I wanted to maintain something like a generic style.scss file under source and combine that with the carbon theme scss source mentioned above and have all of it get bundled into a single bundle.css in a build output folder, I suspect the approach to take would be to use the method described above, but also @import that style.scss file? Then as long as svelte-preprocessor and related rollup plugins are set up to do their jobs correctly, everything should all fall out in one nice bundle.css file in the build output folder?

Appreciate any feedback you can give on my understanding of how carbon theming works!

metonym commented 3 years ago

@nathanblair yes, the approach largely remains the same.

I would recommend using SCSS for custom theming and also for importing individual component styles. The pre-compiled stylesheets from include ALL component styles.

Yes to the the second part of your question. I would recommend copying and customizing the sample SCSS for a theme (e.g., css/g10.scss) by applying the theme overriding logics in this issue.

andreavaccari commented 3 years ago

Hi @metonym, I'm trying to use the style definition in this repository's App.svelte and customize it with the approach detailed in this issue.

The only change I applied was replacing:

:root {
  @include carbon--theme($carbon--theme--white, true) {
    @include emit-component-tokens($tag-colors);
    @include emit-component-tokens($notification-colors);
  }
}

with:

:root {
  @include carbon--theme(
    map-merge(
      $carbon--theme--white,
      (
        interactive-01: red,
        interactive-02: red,
        interactive-03: red,
        interactive-04: red,
      )
    ),
    true
  ) {
    @include emit-component-tokens($tag-colors);
    @include emit-component-tokens($notification-colors);
  }
}

This doesn't work and I can't figure out why. Could you point me in the right direction?

metonym commented 3 years ago

@andreavaccari Try merging your custom theme before the @include:

$feature-flags: (
  enable-css-custom-properties: true,
  ui-shell: true,
  grid-columns-16: true
);

$css--font-face: true;
$css--helpers: true;
$css--body: true;
$css--use-layer: true;
$css--reset: true;
$css--default-type: true;
$css--plex: true;

@import "carbon-components/scss/globals/scss/vendor/@carbon/themes/scss";
@import "carbon-components/scss/globals/scss/component-tokens";
@import "carbon-components/src/components/tag/tag";
@import "carbon-components/src/components/notification/inline-notification";
@import "carbon-components/src/components/notification/toast-notification";

$carbon--theme: map-merge(
  $carbon--theme--white,
  (
    interactive-01: red,
    interactive-02: red,
    interactive-03: red,
    interactive-04: red,
  )
);

:root {
  @include carbon--theme($carbon--theme, true) {
    @include emit-component-tokens($tag-colors);
    @include emit-component-tokens($notification-colors);
  }
}

@import "carbon-components/scss/globals/scss/_css--reset";
@import "carbon-components/scss/globals/scss/_css--font-face";
@import "carbon-components/scss/globals/scss/_css--helpers";
@import "carbon-components/scss/globals/scss/_css--body";
@import "carbon-components/scss/globals/grid/grid";
@import "carbon-components/scss/globals/scss/styles";
andreavaccari commented 3 years ago

Thank you for the quick reply. Sadly the change didn't work. I should mention that we are trying to add Carbon and Sass to a project using Tailwind and Postcss. Also, we don't explicitly import autoprefixer and instead import postcss-preset-env. Does this help figure out what might be going on?

Separately, Carbons reset seems to differ from Tailwind's reset. Is it enough to set $css--reset: false; to disable the former? Are there any flags that must be true in order for the design system to work correctly? Thank you again for your help!

metonym commented 3 years ago

@andreavaccari Were you able to get this to work? https://github.com/IBM/carbon-components-svelte/issues/347#issuecomment-712316505

Autoprefixer should not preclude it from customizing the Carbon theme.

andreavaccari commented 3 years ago

We are still unable to get custom color. If it's not too much to ask, could you review our config below?


* `CarbonUI.svelte`

* `postcss.config.mjs`

module.exports = { // NOTE: the order of the plugins is important. plugins: [ require("postcss-import"), require("tailwindcss"), require("postcss-url")({ url: "inline" }), require("postcss-preset-env")({ stage: 1, features: { "focus-within-pseudo-class": false, }, }), require("autoprefixer")({ overrideBrowserslist: ["last 1 version", "ie >= 11"], }), ], };


* `svelte.config.mjs`

import sveltePreprocess from "svelte-preprocess";

export default { preprocess: sveltePreprocess({ sourceMap: true, postcss: true, sass: true }), };


* `vite.config.mjs`

import { defineConfig } from "vite"; import { svelte } from "@sveltejs/vite-plugin-svelte";

export default defineConfig({ plugins: [svelte()], optimizeDeps: { include: ["clipboard-copy"] }, });

metonym commented 3 years ago

Do you see Carbon styles at all?

andreavaccari commented 3 years ago

Yes we always only see the white theme. The only way in which we managed to change the color of a button was by explicitly setting button-primary inside the map-merge, but obviously this is undesirable because it requires manually setting every color variable.

metonym commented 3 years ago

@andreavaccari I'd recommend asking this in the main Carbon repo. The core team has a much better grasp on SCSS than I do :)