Vaadin Flow/10/11 style component via css - css

My question is pretty basic.
How to add styling from a css-file to a basic vaadin component?
What I do NOT want to use:
PolymerTemplate
getStlye().set(...)
Do I have to #ImportHtml, which includes the css-code or do I have to #StyleSheet with the css-file? And afterwards, do I have to add the "css-style" via .getElement().getClassList().add(...)?
I really need help to have a working simple code example for a Label, Button or whatsever, please. I cannot find anything to satisfy my requirements.

In our documentation we guide to use #ImportHtml in MainView for global styles as a html style module.
In the global style module you can apply themable mixins to change stylable shadow parts, etc. of the components.
In case your target is not in shadow DOM, you can set the styles in custom styles block directly, e.g.
Say you have a Label and TextField in your application
// If styles.html is in src/main/java/webapp/frontend/ path is not needed
#HtmlImport("styles.html")
public class MainLayout extends VerticalLayout implements RouterLayout {
...
Label label = new Label("Title");
label.addClassName("title-label");
add(label);
...
TextField limit = new TextField("Limit");
limit.addClassName("limit-field");
add(limit);
...
}
And in src/main/java/webapp/frontend/styles.html
<custom-style>
<style>
.title-label {
color: brown;
font-weight: bold;
}
...
</style>
</custom-style>
<dom-module theme-for="vaadin-text-field" id="limit-field">
<template>
<style>
:host(.limit-field) [part="value"]{
color:red
}
</style>
</template>
</dom-module>
And your "Title" text will have brown bold font, and the value in text field will be red, but its title un-affected.
See also: Dynamically changing font, font-size, font-color, and so on in Vaadin Flow web apps

Related

Vue conditional style tag in single file component

I have started development on a vue web component library. Members of my team asked for the potential to remove default styles via an HTML attribute on the web component. I know that I could use CSS class bindings on the template elements, however, I was wondering if there is a way to conditionally include the style tag itself so that I would not need to change the class names in order to include the base styles or not.
Example of a component's structure
<template>
<section class="default-class" />
</template>
<script>
export default {
props: {
useDefault: Boolean
}
}
</script>
<style>
// Default styles included here
// Ideally the style tag or it's content could be included based off useDefault prop
</style>
Potential implementation
<web-component use-default="false"></web-component>
As I read your question; you want to keep <style> both affecting Global DOM and shadowDOM
One way is to clone those <style> elements into shadowDOM
But maybe ::parts works better for you; see: https://meowni.ca/posts/part-theme-explainer/
customElements.define("web-component", class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:"open"})
.innerHTML = "<div>Inside Web Component</div>";
}
connectedCallback() {
// get all styles from global DOM and clone them inside the Web Component
let includeStyles = this.getAttribute("clone-styles");
let globalStyles = document.querySelectorAll(`[${includeStyles}]`);
let clonedStyles = [...globalStyles].map(style => style.cloneNode(true));
this.shadowRoot.prepend(...clonedStyles);
}
});
<style mystyles>
div {
background: gold
}
</style>
<style mystyles>
div {
color: blue
}
</style>
<div>I am Global</div>
<web-component clone-styles="mystyles"></web-component>

Where to apply the parent theme class when using :host-context(.theme_name) in Angular2?

I'm building a themed Angular2 app. I have loads of nested components and I would like to change the theme for the whole app by changing one parent class. Let's say one theme is called "theme1". When I apply this to a very parent html-tag, all the nested child components will then switch style by using :host-context, like this:
:host-context(.theme1) .title-toc {
font-family: "bookmania";
font-weight: 700;
font-size: 20pt;
text-transform: uppercase;
color: #a5a5a5;
}
However, where to put this class="theme1"? When I put it to <body>, it worked so the code itself works, but I need to change the theme dynamically so it has to be inside some Angular component instead where I can use [ngClass]. For example inside AppComponent. But when I put it inside app.component (for example router-outlet or any other wrapping tag that should wrap my whole app), it didn't work anymore.
Do I have to make it deep with ::ng-deep somehow or what could be wrong?
You can bind to your root component element's class attribute like this:
export class AppComponent implements OnInit {
#HostBinding('attr.class') mainClass = 'theme1';
changeTheme(theme) {
this.mainClass = theme;
}
}
:host-context() sees the classes applied on the document body. You can set the class of body with JavaScript after the application has loaded, like this:
var myclass = "my-theme-name";
document.querySelector('body').classList.add(myclass);
This way you can load the theme name even from server and then apply it to the body from any Angular2 component via JS:
:host-context(.my-theme-name) .my-theme-specific-style

Applying dynamic styling to injected HTML in Angular 2

For an Angular project I'm working on, I'm injecting HTML into a <div> like so:
<div class="myClass" [innerHTML]="htmlToInsert"></div>
The htmlToInsert contains a variety of things, notably <a> tags. Previously we were styling all these tags like so:
.myClass ::ng-deep a {
color: #f00;
text-decoration: none;
}
And this worked fine. But now I need the color of these links to be dynamically generated during component initialization, based on data coming in from elsewhere. All of the dynamic styling I've seen in Angular requires you to apply things directly to the HTML tag, but we don't have them here to work with.
How can I apply dynamic styling to HTML that is also dynamically generated? Can I directly change the CSS class somehow? Would using a pipe be the correct approach here? Is there another method I don't know about? I could maybe refactor code if there is absolutely no other way of doing this.
So if you can't modify the innerHTML you are passing in, you can achieve this functionality with a custom directive. Essentially you would tag your div that contains your innerHTML with a custom directive. That directive then looks for any anchor tags in it and changes the color based on an input.
// component.html
<div anchorColor [color]="dynamicColor" [innerHTML]="htmlToInsert"></div>
// directive.ts
#Directive({selector: '[anchorColor]'})
export class AnchorColorDirective implements OnAfterViewInit {
#Input() color: string;
constructor(private el: ElementRef){
}
// afterViewInit lifecycle hook runs after DOM is rendered
ngAfterViewInit(){
// get anchor element
let anchorEl = this.el.nativeElement.querySelector('a');
// assign color
if(anchorEl){
anchorEl.style.color = this.color;
}
}
}
Here is a working plunkr https://plnkr.co/edit/QSYWSeJaoUflP94Cy4Hm?p=preview

Dynamically inject shared styles in polymer element (polymer 1.2.3)

I do have several nested polymer elements created by myself. Currently with using polymers shared styles I'm able to inject custom styling into other elements. Unfortunately this approach is restricted to static use. So at implementation time I do need to know which Element should use which shared style by import the shared style module with <link rel="import" href="my-shared-style.html"> and <style include="my-shared-style"></style>.
But in my use case I do need to inject shared styles into polymer elements at runtime. Is there any possibility to achieve this?
UPDATE
I tried following approach inspired by Günters answer below:
Polymer({
is : 'html-grid-row',
/**
* Inject style into element
* #param {string} style
*/
injectStyle : function(style) {
var customStyle = document.createElement('style', 'custom-style');
customStyle.textContent = style;
Polymer.dom(this.root).appendChild(customStyle);
}
/**
* Additional Elements JS functionality is put here...
*
*/
)}
When I now try to dynamically add style by calling injectStyle('div {font-weight: bold;}') on elements instance at runtime the style module is injected into the element but is not displayed because polymer seems to edit custom-styles text content like the following:
<style is="custom-style" class="style-scope html-grid-row">
div:not([style-scope]):not(.style-scope) {font-weight: bold;}
</style>
Is there a way to prevent polymer from adding the :not([style-scope]):not(.style-scope) prefix to style rules?
UPDATE 2:
Referencing a global shared style using include='my-shared-style' does have the same effect.
Include this shared style which is statically imported globally using html import:
<dom-module id="my-shared-style">
<template>
<style>
div {
font-weight: bold;
}
</style>
</template>
</dom-module>
After dynamically import and referencing shared-style Polymer includes following:
<style is="custom-style" include="my-shared-style" class="style-scope
html-grid-row">
div:not([style-scope]):not(.style-scope) {
font-weight: bold;
}
</style>
SOLUTION
Finally I used a workaround for dynamically inject styling into Polymer elements at runtime by extending the <style> HTML Element with document.register('scoped-style', {extends : 'style', prototype : ...}). The injectStyle(style) method (see above) now creates a <style is="scoped-style"> element directly as child of the Elements root node. Indeed it's inspired by https://github.com/thomaspark/scoper. This works so far for me.
I used something like this successfully to inject styles dynamically
var myDomModule = document.createElement('style', 'custom-style');
myDomModule.setAttribute('include', 'mySharedStyleModuleName');
Polymer.dom(sliderElem.root).appendChild(myDomModule);
The style-module 'mySharedStyleModuleName' needs to be imported somewhere (like index.html).
See also https://github.com/Polymer/polymer/issues/2681 about issues I run into with this approach and https://stackoverflow.com/a/34650194/217408 for more details

Css doesn't work for a custom fxml component

I use the following CSS to change the font of some components which are placed on a custom JavaFX AnchorPane, defined as fx:root. But the font-size remains default.
* {
-fx-font-family : Arial;
}
.label, .textField, .textfield, .checkBox, .text{
-fx-font-size: 18;
}
I got that I should change them using the ids of all inner components but it's not a good idea, because it results in redundant code.
Then I got that applying it on the main style class, it will work. But the sad story is that * can't be overriden. (I have defined * selector in a global css class for my whole application.
Try .root instead of *.
For the font size, some of your class names are wrong. Try
.label, .text-field, .check-box, .text {
-fx-font-size: 18pt ;
}
Style classes are documents in the CSS Reference Guide
Note that Text nodes have empty style class, so you need to explicitly set the style class for your text nodes.

Resources