I am building a Polymer Single Page Interface with a lot of custom elements.
Now I want my elements to have some sort of master style, which I can define in the index.html or my main content element. Think of it like this:
index.html
<style>
.classWhichWillBeUsedInCustomElements {
mainColor: #e0e0e0;
}
</style>
or
<script>
mainColor = "#e0e0e0";
</script>
my-cool-element.html
<polymer-element name="my-cool-element">
<template>
<paper-button style="color: {{mainColor}}"></paper-button>
</template>
</polymer-element>
or
<polymer-element name="my-cool-element">
<template>
<style>
.coolButton {
width: 300px;
color: {{mainColor}};
}
</style>
<paper-button class="coolButton"></paper-button>
</template>
</polymer-element>
Except that this doesn't work.
I have tried:
Creating a global variable window.defaultColor and using it like color: {{defaultColor}};
Using core-style in a parent element, without much luck
Creating a css class in my index.html and calling it in a custom element
What is the right way to achieve this? I am trying to avoid using Less
Use the following pattern in the index.html or a global stylesheet:
<style>
body /deep/ .classWhichWillBeUsedInCustomElements {
mainColor: #e0e0e0;
}
</style>
Then you could use the class within the custom element. The global style will punch the shadow boundary. You could replace body with any other element or selector under which you want to punch the shadow dom boundary.
More on deep here: https://www.polymer-project.org/0.5/articles/styling-elements.html#cat
Related
I'm using css variables in my component and set the width of a div based on data computed in the setup()
setup(props) {
const progressBar = PositionService.getProgressBar(props.position);
const progressWidth = `${progressBar}%`;
...
return { ..., progressWidth };
}
Then I'm using this variable as css variable.
<style lang="scss" scoped>
.progress-bar-width {
--progress-bar-width: v-bind("progressWidth");
width: var(--progress-bar-width);
}
</style>
When rendering the page i noticed that an inline style is added to the html parent component resulting in
.....
The CSP is blocking inline style so this approach doesn't work.
How can I use css variables without inline style?
It's a hacky solution but with the handicap of no inline styles it's the only thing I can think of:
Add a "style" component to your template. This will be replaced with <style> tags in the DOM. Inside the component add the desired CSS variable to :root
<component :is="`style`">
:root { --progress-bar-width: {{ progressWidth }}; }
</component>
<div class="progress-bar-width"></div>
<style lang="scss" scoped>
.progress-bar-width {
width: var(--progress-bar-width);
}
</style>
how about use inline style?
https://vuejs.org/guide/essentials/class-and-style.html#binding-inline-styles
<div :style="`--progress-bar-width:${progressWidth}`" >
your component
</div>
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
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>
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
I'm trying to style the root element of a polymer element with css. Take the counter-click for example. If I have a polymer element in my main html and I want to give it a size (say width and height.) I try to use a global css in my main html like
click-counter{
width:100px;
height:100px;
}
This doesn't work.
I also tried to style inside the polymer element like
<polymer-element name="click-counter" attributes="count">
<template>
<style>
#host{
click-counter {
width:100px;
height:100px;
}
}
...
This doesn't work either. Does anyone know how am I gonna style the element with css?
(I'm using dart 0.8.1.2)
Thanks,
Yi
The click-counter is composed of a button and a text input. There is no div that holds the 2 together. So if you are setting the width and height on the component, what are you really setting it on?
<polymer-element name="click-counter">
<template>
<button on-click="increment">Click Me</button>
<p>You clicked the button {{count}} times.</p>
</template>
<script type="application/dart" src="click_counter.dart"></script>
</polymer-element>
In case there would be a div wrapping the button and the text input, you could set the width of the div in the component like this:
<polymer-element name="click-counter">
<template>
<style type="text/css">
div{
width:100px;
border-style:solid;
background-color: #FF9900;
font-weight: bold;
}
</style>
<div>
<button on-click="increment">Click Me</button>
<p>You clicked the button {{count}} times.</p>
</div>
</template>
<script type="application/dart" src="click_counter.dart"></script>
</polymer-element>
You can also declare a div style on the index file, but then you have to set applyAuthorStyles to true on the component.
#CustomTag('click-counter')
class ClickCounterElement extends PolymerElement with ObservableMixin {
#observable int count = 0;
get applyAuthorStyles => true;
void increment(Event e, var detail, Node target) {
count += 1;
}
}
This would affect all divs on the page though. I'm not sure how you would select only the root div in the click-counter component.
Is this what you want to do?
#host {
:scope {
...
}
}
See this section of the tutorial: Styling a custom element