title: VueJS - Apply styles to slots wrapping elements
body: <p>I want to create a <code>Card</code> component using vue that has a header and content section using the <a href="https://v2.vuejs.org/v2/guide/components-slots.html" rel="nofollow noreferrer">vuejs slots api</a>.</p>
  <p>I am having trouble understanding how I can create a structure in my Card component. The card should contain all the wireframe styles (padding &amp; margin), but be open for extension from the child template that uses the component.</p>
  <p>I would like to know if there are any standard ways of styling wrapper elements with slots inside them from the child component.</p>
  <p>The basic <code>Card</code> element has 2 slots wrapped with structural elements that I would like to allow the child template to modify where necessary.</p>
  <pre><code>&lt;div class=&quot;Card&quot;&gt;
    &lt;header class=&quot;CardHeader&quot;&gt;
      &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
    &lt;/header&gt;
    &lt;div class=&quot;CardContent&quot;&gt;
      &lt;slot&gt;&lt;/slot&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  <p>Ideally I would like to add a <code>:class</code> attribute to the <code>#slot</code> element and have that be used on the element in the slot, however, it seems that the old syntax has been depreciated in the newest version of the framework eg.</p>
  <pre><code>&lt;Card&gt;
    &lt;template #header class=&quot;extendHeader&quot;&gt;
      stuff
    &lt;/template&gt;
  &lt;/Card&gt;
  </code></pre>
  <p>I can think of 3 ways to do it that <strong>will</strong> work, each with their drawbacks.</p>
  <ol>
  <li>Use props to add a class via the root element</li>
  <li>Use a class on the root element and have style hooks on the components elements</li>
  <li>Wrap the slot content in another element</li>
  </ol>
  <p>A must for my project is using css-modules to reduce as much global css as possible because it has caused me so much grief in the past.</p>
  <h3>1. Use props to add a class via the root element</h3>
  <p>This method would allow me to use css-modules and would make the <code>Card</code> elements open for extension</p>
  <p>The component template would need to compose extra styles from the child template</p>
  <pre><code>&lt;header :class=&quot;$style.Header, ...headerClasses]&quot;&gt;
    &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
  &lt;/header&gt;
  </code></pre>
  <p>The child template can then use <code>:header-classes</code> to extend the base Card classes, or overwrite unwanted styles.</p>
  <pre><code>&lt;Card :header-classes=&quot;[$style.header]&quot;&gt;
    &lt;template #header&gt;
      stuff
    &lt;/template&gt;
  &lt;/Card&gt;
  &lt;style module&gt;
    .header {
      background: var(--v-blue);
    }
  &lt;/style&gt;
  </code></pre>
  <h3>2. Use a class on the root element and have style hooks on the components elements</h3>
  <p>The <code>Card</code> template would need to assign extra classes that could be used to extend the base structural components of the component. The css-module classes should not be used as the names are hashed to avoid collisions.</p>
  <pre><code>&lt;div :class=&quot;[$style.Card, 'CardStyleHook']&quot;&gt;
    &lt;header :class=&quot;[$style.Header, 'CardHeaderStyleHook']&quot;&gt;
      &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
    &lt;/header&gt;
    &lt;div :class=&quot;[$style.Content, 'CardContentStyleHook']&quot;&gt;
      &lt;slot&gt;&lt;/slot&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  <p>Then a single class could be added to the component and styles to the extra classes could be used</p>
  <pre><code>&lt;Card :class=&quot;$style.extendCard&quot;&gt;
    &lt;template #header&gt;
      stuff
    &lt;/template&gt;
  &lt;/Card&gt;
  &lt;style module&gt;
    .extendCard .CardHeaderStyleHook {
      background: var(--v-blue);
    }
  &lt;/style&gt;
  </code></pre>
  <h3>3. Wrap the slot content in another element</h3>
  <p>I think this kind of defeats the purpose of slots, and it will lead to issues where I need to remove the padding from the wrapping structural element in the <code>Card</code>, it's not really open for extension and would require more workarounds to allow this style to work.</p>
  <pre><code>&lt;Card&gt;
    &lt;template #header&gt;
      &lt;div :class=&quot;$style.customHeader&quot;&gt;
        stuff
      &lt;/div&gt;
    &lt;/template&gt;
  &lt;/Card&gt;
  &lt;style module&gt;
    .customHeader{
      background: var(--v-blue);
    }
  &lt;/style&gt;
  </code></pre>
  <p>Is there any standard way to handle these cases since the old slots have been depreciated? have I missed something in the documentation, I have only been playing with vue for a couple of days so it's definitely possible.</p>
  <p>There is full examples in the snippet below with working code if you need to provide any examples.</p>
  <p>Thanks for any help!</p>
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="false" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>const use$styleMocking = {
    beforeMount() {
      // mock css-modules output
      this.$style = {
        Card: 'Card__x1337',
        Header: 'CardHeader__x1337',
        Content: 'CardContent__x1337',
      }
    }
  }
  
  Vue.component('Card', {
    template: '#card-template',
    mixins: [ use$styleMocking ],
    props: {
      cardClasses: { default: () =&gt; [] },
      headerClasses: { default: () =&gt; [] },
      contentClasses: { default: () =&gt; [] },
    }
  })
  
  Vue.component('style-hooked-card', {
    template: '#style-hooked-card-template',
    mixins: [ use$styleMocking ]
  })
  
  const app = new Vue({
    el: '#app',
    template: '#app-template'
  })</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>:root {
    --white: #fff;
    --v-teal: #00c58e;
    --v-jade: #108775;
    --v-blue: #2f495e;
    --card-padding: 0.5rem 1rem;
    --grid-gap: 1.25rem;
  }
  
  html, body {
    font-family: sans-serif;
    line-height: 1.44;
  }
  
  .main {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-column-gap: var(--grid-gap);
    grid-row-gap: var(--grid-gap);
  }
  
  /* --------- Card Styles --------- */
  /*
    styles have __x1337 to mock css-modules, the client should never know the hash
    and should not use it to style elements
  */
  .Card__x1337 {
    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
    transition: 400ms box-shadow;
    margin: 0;
    flex: 1;
  }
  .CardHeader__x1337 {
    padding: var(--card-padding);
    background: var(--v-teal);
  }
  .CardHeader__x1337 h3 {
    color: var(--v-blue);
    margin: 0;
    padding: 0;
    font-size: 1rem;
  }
  .CardContent__x1337 {
    padding: var(--card-padding);
  }
  /* --------- End Card Styles --------- */
  
  .extendHeader {
    background: var(--v-blue);
  }
  
  .extendHeader h3 {
    color: var(--white);
  }
  
  .extendCard .CardHeaderStyleHook {
    background: var(--v-jade);
  }
  
  .extendCard .CardHeaderStyleHook h3 {
    color: var(--white);
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"&gt;&lt;/script&gt;
  
  &lt;template type="text/x-template" id="app-template"&gt;
    &lt;main class="main"&gt;
      &lt;Card&gt;
        &lt;template #header class="extendHeader"&gt;
          &lt;h3&gt;Basic Card Styles&lt;/h3&gt;
        &lt;/template&gt;
        &lt;template&gt;
          &lt;p&gt;It would be ideal to add a class to the template and have it available to add to the classes of the wrapper element around slots&lt;/p&gt;
        &lt;/template&gt;
      &lt;/Card&gt;
      
      &lt;Card :header-classes="['extendHeader']"&gt;
        &lt;template #header&gt;
          &lt;h3&gt;1. Extend Header Styles&lt;/h3&gt;
        &lt;/template&gt;
        &lt;template&gt;
          &lt;p&gt;This card uses props on the Card to extend the wrapper class, this example is using a global class, but this would use css-modules locally scoped classes correctly&lt;/p&gt;
        &lt;/template&gt;
      &lt;/Card&gt;
      
      &lt;Style-Hooked-Card class="extendCard"&gt;
        &lt;template #header&gt;
          &lt;h3&gt;2. Extend Card Styles&lt;/h3&gt;
        &lt;/template&gt;
        &lt;template&gt;
          &lt;p&gt;This card adds a hook class to every component so that it can be extended from the outside&lt;/p&gt;
        &lt;/template&gt;
      &lt;/Style-Hooked-Card&gt;
    &lt;/main&gt;
  &lt;/template&gt;
  
  &lt;template type="text/x-template" id="card-template"&gt;
    &lt;div :class="[$style.Card, ...cardClasses]"&gt;
      &lt;header :class="[$style.Header, ...headerClasses]"&gt;
        &lt;slot name="header"&gt;&lt;/slot&gt;
      &lt;/header&gt;
      &lt;div :class="[$style.Content, ...contentClasses]"&gt;
        &lt;slot&gt;&lt;/slot&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/template&gt;
  
  &lt;template type="text/x-template" id="style-hooked-card-template"&gt;
    &lt;div :class="[$style.Card, 'CardStyleHook']"&gt;
      &lt;header :class="[$style.Header, 'CardHeaderStyleHook']"&gt;
        &lt;slot name="header"&gt;&lt;/slot&gt;
      &lt;/header&gt;
      &lt;div :class="[$style.Content, 'CardContentStyleHook']"&gt;
        &lt;slot&gt;&lt;/slot&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/template&gt;
  
  &lt;div id="app"&gt;&lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>