Vue styling local components - css

I have Single-File Components and I want to use it in different places like subscribe page and footer.
But I want to style to be different.
Is it possible to style local components?
Component file: Newsletter.vue
<template>
<form>
<label>Enter your email address here</label>
<input type="text" name="email" required/>
</form>
<button #click="subscribe" >
SUBSCRIBE
</button>
</template>
Subscribe page: Subscribe.vue
let say style Newsletter background-color green and align to left
<template>
<h2>
Subscribe to receive Newsletter
</h2>
<Newsletter></Newsletter>
</template>
<script>
import Newsletter from "#/components/Newsletter.vue";
export default {
components: {
Newsletter
}
}
</script>
<style scoped>
Newsletter{
background-color: green;
text-align:left;
}
</style>
Subscribe page: Footer.vue
but in Footer, I want to style Newsletter background-color red and align center
<template>
<h2>
JOIN OUR NEWSLETTER
</h2>
<Newsletter></Newsletter>
</template>
<script scoped>
import Newsletter from "#/components/Newsletter.vue";
export default {
components: {
Newsletter
}
}
</script>
<style>
Newsletter{
background-color: red;
text-align:center;
}
</style>

This is possible! All you have to do is add the scoped attribute to the style tag.
Here is the snippet from the docs just for reference here:
<template>
<button class="btn btn-close">X</button>
</template>
<style scoped>
.btn-close {
background-color: red;
}
</style>
This will only apply the styles locally, to the component which contains the style tag. Keep in mind though, you really should avoid using tag selectors because they are the most generic. It's a better practice to use a class selector because it has a higher specificity, meaning it is less likely to be over-written (id selectors or inline styles take precedence). I would suggest doing something like this:
<template>
<h2>
Subscribe to receive Newsletter
</h2>
<Newsletter class="newsletter"></Newsletter>
</template>
<script>
import Newsletter from "#/components/Newsletter.vue";
export default {
components: {
Newsletter
}
}
</script>
<style scoped>
.newsletter {
background-color: green;
text-align:left;
}
</style>
In the example above, the newsletter class will make the background-color green only in this single-file component.

There are many options. You may benefit from using the ::v-deep combinator which allows leaking the style to the child components.
Using your example with a small change:
<template>
<h2>
Subscribe to receive Newsletter
</h2>
<Newsletter class="newsletter"></Newsletter>
</template>
<script>
import Newsletter from "#/components/Newsletter.vue";
export default {
components: {
Newsletter
}
}
</script>
<!-- this is the change. Updated to have `::v-deep` to allow style to "leak" to the child component -->
<style scoped>
::v-deep .newsletter {
background-color: green;
text-align:left;
}
</style>
See more at:
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors
Another option to consider is using global style in place of the local style and be sure that each shared class element has a unique parent.
In one component such as Subscribe:
<style lang="scss">
.subscribe {
.newsletter {
// style for this specific version of newsletter
}
}
</style>
In another component where ".somethingelse" should be the specific type of component:
<style lang="scss">
.somethingelse {
.newsletter {
// style for this other specific version of newsletter
}
}
</style>
More info about global specificity:
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Related

Vue 3 slot styles from child component

Summary: I need to style the contents of a <slot>, from the child component. I'm using scoped css and the styles don't apply:
I have the following two components:
<!-- Parent.vue -->
<template>
<h1>{{ msg }} from Parent</h1>
<Child>
<h1>{{ msg }} from Child</h1>
</Child>
</template>
...
<style scoped>
h1 {
color: green;
}
</style>
<!-- Child.vue -->
<template>
<slot></slot>
</template>
...
<style scoped>
h1 {
color: red;
}
</style>
I want the 2nd <h1> to be red, but it's green, since the component is rendered with something like:
<h1 data-v-452d6c4c data-v-2dcc19c8-s>Hello from Child</h1>
<style>
h1[data-v-452d6c4c] {
color: green;
}
h1[data-v-2dcc19c8] {
color: red;
}
</style>
data-v-452d6c4c comes from Parent, and data-v-2dcc19c8-s from Child
If the second attribute, in the <h1> tag, was just data-v-2dcc19c8 the style I wanted would be applied, but since it has that -s suffix (slot?), it doesn't.
I could probably find some other solution with a class or something, but I rarely use <slot> and I want to understand the inner workings. That -s tells me that what I'm trying to do can be dealt with the help of the framework, what am I missing?
A working sample:
https://codesandbox.io/s/condescending-brown-ilfwn
Use the new :slotted selector in Vue 3:
Child.vue
<template>
<slot></slot>
</template>
<script>
export default {
name: "Child",
};
</script>
<style scoped>
:slotted(h1) {
color: red !important;
}
</style>
In Vue 3, child scoped styles don't affect slotted content by default.
In your particular example, the !important modifier is also necessary because the parent also defined an h1 style which would take precedence otherwise

Overriding the encapsulated :host-style of external component

Is it possible to override :host-styling of an external angular2-component?
We're making a library including a sidebar-component. This component has a default (fallback) background, but this should be overridable by css/theme used in the app.
#Component({
selector: 'sidebar',
styles: [`
:host { background-color: green; }
`],
template: `
<h1>sidebar</h1>
<ng-content></ng-content>
`
})
export class SideBarComponent { .... }
Main App css:
<style>
sidebar {background: red; color: yellow; }
</style>
This returns a sidebar with green background and yellow text, but I want a red background...
Edited:
As found on http://blog.angular-university.io/how-to-create-an-angular-2-library-and-how-to-consume-it-jspm-vs-webpack/: add an attribute to the body-tag:
<body override>
<app></app>
</body>
And in your css: use a selector for this attribute:
[override] hello-world h1 {
color:red;
}
This way, your css does not have to be parsed.
Previous solution:
I've found a solution myself: instead of linking my (theming) css-file in index.html, which isn't parsed, I imported this particular css-file in the app.component.ts annotation.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet/css" type="text/css" href="/assets/style/app.css" />
</head>
<body>
<app></app>
</body>
</html>
app.component.ts:
import { ... }
#Component({
selector: 'app',
styles: [`
#import "assets/style/theme.css";
`],
template: `
...`,
})
export class AppComponent {...}
theme.css:
sidebar {background: red; }
Its not possible to overwrite styles set in a component's styles this way. See point 3 on the "Using Component Styles" section in the Component Styles docs (https://angular.io/docs/ts/latest/guide/component-styles.html)
Our component's styles cannot be changed by changes to styles
elsewhere in the application.
Using :host-context is probably a nicer way to acheive this (although i have never tried myself).
You should try to check the same with host-context. As per documentation host-context works just like the function form of :host(). It looks for a CSS class in any ancestor of the component host element, all the way up to the document root. It's useful when combined with another selector.
In the following example, we apply a background-color style to all <h2> elements inside the component, only if some ancestor element has the CSS class theme-light.
:host-context(.theme-light) h2 {
background-color: #eef;
}

How to use component variable within css / style tag in Angular 2?

How can I use component variables within style TAG in Angular 2?
I do have an Angular 2 component for my header which I like to color depending on a users setting. Thus I'd like to assign an background and font color. While I know how to to this with an attribute binding to an element, I couldn't figure out how to use in a style tag.
Using attribute binding for style works well, however this gets pretty anoying for several subelements, especially if they are nested within other sub components. [ngStyle]= attribute is also only working on a single element.
<header id="header" [style.background-color]="changeBackground()">
<div>
Some Text
Some Link
<subcomponent></subcomponent>
</div>
<div> ... a lot mor stuff </div>
</header>
Thus I'd like to add something like
<style>
#header, #header a {
color: {{mycolor}};
}
</style>
to the html template. However this is not working
Similar Questions do not answer this question yet and only show attribute binding as a solution:
Angular2 dynamic change CSS property
Dynamically updating css in Angular 2
https://scotch.io/tutorials/all-the-ways-to-add-css-to-angular-2-components
https://coryrylan.com/blog/introduction-to-angular-2-ngclass-and-ngstyle
It looks to me like you are just creating a new component called 'subcomponent', why not do that?
subcomponent.ts:
import { Component } from '#angular/core';
#Component({
selector: 'subcomponent',
templateUrl: './subcomponent.html',
})
export class SubComponent {
mycolor = 'blue';
}
subcomponent.html:
<style>
#header, #header a {
color: {{mycolor}};
}
</style>
To your #Component object, add
styles:[ `#header, #header a {
color: {{mycolor}};
}`]
So for example:
#Component({
template: `<header id="header" [style.background-color]="changeBackground()">
<div>
Some Text
Some Link
<subcomponent></subcomponent>
</div>
<div> ... a lot mor stuff </div>
</header>`,
styles: [ `#header, #header a {
color: {{mycolor}};
}`
`]
})
Use NgStyle as explained in this answer
https://stackoverflow.com/a/41903349
in short
<header id="header" [ngStyle]="getStyle()">
<div>
Some Text
Some Link
<subcomponent></subcomponent>
</div>
<div> ... a lot mor stuff </div>
</header>
and
getStyle(): any {
return {"background-color" : this.changeBackgroundColor()};
}

Polymer Styling Child Components

I am trying to style my child components. Isit wrong to put the style in a parent component? It appears that does not work.
I put the style for .card-page in the top level element (containing expenses-module where I use it)
<dom-module id="expenses-app">
<template>
<style>
...
.card-page {
display: block;
width: 100%;
}
</style>
<app-drawer-layout>
<app-header-layout>
...
<iron-pages selected="{{routeData.view}}" attr-for-selected="name">
<dashboard-module name="dashboard" route="{{subroute}}"></dashboard-module>
<expenses-module name="expenses" route="{{subroute}}"></expenses-module>
<settings-module name="settings" route="{{subroute}}"></settings-module>
</iron-pages>
</app-header-layout>
</app-drawer-layout>
</template>
In expenses module,
<paper-card heading="Expenses" class="card-page">...
</paper-card>
Seems like if I move the styles into expenses-module it works.
You cannot directly style elements inside custom element from their parents like that, because Polymer processes the style within <dom-module> and will apply styles only to direct child members. It will not descend into child custom elements.
In other words, standard CSS selectors will only work within the scope of the declaring component. Both in Shadow and Shady DOM.
For your styles to work with nested elements, you should use CSS mixins and properties. All PolymerElements and many 3rd party elements will come with such styling extension points. The naming usually follow the convention, where the main mixin is called same as the element itself. Additionally, there may be more specific mixins and properties, which style only parts of the element. <paper-card> docs for example lists --paper-card mixin, --paper-card-content mixin, --paper-card-header-color and more.
If you want to better control the styling of elements you use, you would want to create your own CSS mixins/properties and #apply() them to selected elements. See how in the example below --my-elem-card-page applies only to one of the two paper cards.
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import"/>
<link href="paper-card/paper-card.html" rel="import"/>
</head>
<body>
<my-wrapper></my-wrapper>
<dom-module id="my-elem">
<template>
<style>
.card-page {
#apply(--my-elem-card-page);
}
</style>
<paper-card heading="my-elem specific style" class="card-page">
<div class="card-content">
Content here
</div>
</paper-card>
<paper-card heading="Default style" class="unstyled-page">
<div class="card-content">
Content here
</div>
</paper-card>
</template>
</dom-module>
<dom-module id="my-wrapper">
<template>
<style>
# will be ignored
paper-card {
width: 200px;
}
my-elem{
--paper-card: {
color: blue;
display: block;
}
}
my-elem {
--my-elem-card-page: {
color: red;
}
}
</style>
<my-elem></my-elem>
</template>
</dom-module>
<script>
Polymer({
is: 'my-elem'
});
Polymer({
is: 'my-wrapper'
});
</script>
</body>
</html>

How to override parent style when extending a polymer element

I have one element that extends another and I'm having trouble getting the styling to override the parent using the example in the documentation. For example, say I want to style the praise in the parent element:
<polymer-element name="polymer-cool">
<template>
<style>
:host #p {
color: red;
}
</style>
You are <span id='p'>{{praise}}</span> <content></content>!
</template>
...
</polymer-element>
but change that in an extension of that element:
<polymer-element name="polymer-cooler" extends="polymer-cool">
<template>
<!-- A shadow element render's the extended
element's shadow dom here. -->
<style>
#p {
color: blue;
}
</style>
<shadow></shadow> <!-- "You are cool Matt" -->
</template>
...
</polymer-element>
You can see in the JSfiddle below, that I haven't been able to change the color of the span#p. I've tried a few other things like
polymer-cooler #p {
color: blue;
}
And tried putting the style inside of the tags, but no luck. Hoping it's possible and I'm just missing something.
http://jsfiddle.net/jamstooks/tpyL9/
Well, this looks like this works. I'd love to get some clarification from someone on whether this is the best way to do this:
<polymer-element name="polymer-cooler" extends="polymer-cool">
<template>
<style>
{
:host::shadow #p
color: blue;
}
</style>
<shadow></shadow>
</template>
...
</polymer-element>
http://jsfiddle.net/jamstooks/tpyL9/4/
EDIT: 7/22/14
Per the comment from Scott below, I have updated the code above from :host /deep/ #p to :host::shadow #p

Resources