Changing the background-color in vaadin-text-field using Vaadin 14

I have a application that used Vaadin 10 and changed the background color of a vaadin text field using the following in a my-text-field.html file.

<dom-module id="my-text-field" theme-for="vaadin-text-field">
    <template>    
         <style include="vaadin-text-field-default-theme"> 
            :host(.custom-style) [part="input-field"]
 {  
               background-color:  #909090 ;   
            }            
            :host(.ok) [part="input-field"]
 {  
               background-color:  #40bf80;   
            }            
            :host(.nok) [part="input-field"]
 {  
               background-color:  #ff0000;   
            }
            :host(.init) [part="input-field"]
 {  
               background-color:  #909090;   
            }
            :host(.view-toolbar__search-field) [part="input-field"]
 {
               background-color:  #909090;               
            }           
        </style>
    </template>

    <!-- Polymer boilerplate to register the my-text-field element -->
    <script>
        class MyTextFieldElement extends Polymer.Element {
            static get is() {
                return 'my-text-field'
            }

            _isEmpty(array) {
                return array.length == 0;
            }
        }
        customElements.define(MyTextFieldElement.is, MyTextFieldElement);
    </script>

</dom-module>

In the Java class that extended the PolymerTemplate I used a

@HtmlImport("frontend://src/views/paymentslist/my-text-field.html")

How do I do this with Vaadin 14 ?

I have tried the following for Vaadin 14 by creating a my-text-field.js file

import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
import '@vaadin/vaadin-text-field/vaadin-text-field.js';

//set your custom CSS rules for button.
//Use an unique id for the dom-module.
const $_documentContainer = html`
<dom-module id="my-text-field"
           theme-for="vaadin-text-field">
      <template>
         <style include="vaadin-text-field-default-theme"> 
            :host(.custom-style) [part="input-field"]
 {  
               background-color:  #909090 ;   
            }            
            :host(.ok) [part="input-field"]
 {  
               background-color:  #40bf80;   
            }            
            :host(.nok) [part="input-field"]
 {  
               background-color:  #ff0000;   
            }
            :host(.init) [part="input-field"]
 {  
               background-color:  #909090;   
            }
            :host(.view-toolbar__search-field) [part="input-field"]
 {
               background-color:  #909090;               
            }           
        </style>
    </template>
</dom-module>`;

document.head.appendChild($_documentContainer.content);

and used a @JsModule to import it in the Java class that extends the PolymerTemplate

@JsModule("./src/views/paymentslist/my-text-field.js")

However it doesn’t seem to work and I am not sure what I am doing wrong.

Grateful for any suggestions.

Thanks, John.

Hi John!

If you are simply trying to add style customizations for the Vaadin Text Field component, here’s what you need:

A plain CSS file, for example /frontend/styles/text-field.css:

:host(.custom-style) [part="input-field"]
 {  
   background-color:  #909090 ;   
}            
:host(.ok) [part="input-field"]
 {  
   background-color:  #40bf80;   
}            
:host(.nok) [part="input-field"]
 {  
   background-color:  #ff0000;   
}
:host(.init) [part="input-field"]
 {  
   background-color:  #909090;   
}
:host(.view-toolbar__search-field) [part="input-field"]
 {
   background-color:  #909090;               
}    

Use the @CssImport annotation, probably at the main class of your app:

@CssImport(value = "./styles/text-field.css", themeFor = "vaadin-text-field")

Your previous solution seemed unnecessarily complex, by the way. You don’t need to extend a PolymerTemplate or Polymer.Element in the client-side to make style customizations, and you don’t need to re-include any additional style modules (like you did with “vaadin-text-field-default-theme”).

Before Vaadin 14 you only needed a single HTML file with a style module (i.e. dom-module with just a <style> in the template) and the @HtmlImport annotation like you had before (probably in the main class of your app):

<dom-module id="my-text-field" theme-for="vaadin-text-field">
    <template>    
         <style> 
            :host(.custom-style) [part="input-field"]
 {  
               background-color:  #909090 ;   
            }            
            :host(.ok) [part="input-field"]
 {  
               background-color:  #40bf80;   
            }            
            :host(.nok) [part="input-field"]
 {  
               background-color:  #ff0000;   
            }
            :host(.init) [part="input-field"]
 {  
               background-color:  #909090;   
            }
            :host(.view-toolbar__search-field) [part="input-field"]
 {
               background-color:  #909090;               
            }           
        </style>
    </template>
</dom-module>

Thanks, Jouni. That helped a lot and now works.

If I have my own element … example something like the vaadin example review list element

import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
import '@vaadin/vaadin-button/vaadin-button.js';
import '@vaadin/vaadin-text-field/vaadin-text-field.js';
import '@polymer/iron-icon/iron-icon.js';

class ReviewListElement extends PolymerElement {
  static get template() {
    return html`
        <style include="lumo-color lumo-typography lumo-badge view-styles">
            :host {
                display: block;
            }

            #header {
                display: flex;
                justify-content: space-between;
                flex-wrap: wrap;
                align-items: baseline;
            }

            .reviews__no-matches {
                display: flex;
                align-items: center;
                justify-content: center;
                height: 4em;
                font-size: 22px;
                color: var(--lumo-tertiary-text-color);
            }

            /* Small viewport styles */

            @media (max-width: 500px) {
                .review {
                    padding: var(--lumo-space-m);
                    padding-right: var(--lumo-space-s);
                    flex-wrap: wrap;
                }

                .review__date {
                    order: 1;
                    margin-left: 3.5em;
                    margin-top: 0.5em;
                }
            }

        </style>

        <div class="view-toolbar">
            <vaadin-text-field id="search" class="view-toolbar__search-field" autocapitalize="off">
                <iron-icon icon="lumo:search" slot="prefix"></iron-icon>
            </vaadin-text-field>
            <vaadin-button id="newReview" class="view-toolbar__button" theme="primary">
                <iron-icon icon="lumo:plus" slot="prefix"></iron-icon>
                <span>[[reviewButtonText]
]</span>
            </vaadin-button>
        </div>

        <div class="view-container reviews">
            <h2 id="header"></h2>
            <template is="dom-if" if="{{!_isEmpty(reviews)}}">
                <template is="dom-repeat" items="[[reviews]
]">
                    <div class="review">
                        <div class="review__rating">
                            <p class="review__score" data-score\$="[[item.score]
]">[[item.score]
]</p>
                            <p class="review__count">
                                [[item.count]
]
                                <span>times tasted</span>
                            </p>
                        </div>
                        <div class="review__details">
                            <h4 class="review__name">{{item.name}}</h4>
                            <template is="dom-if" if="[[item.category]
]">
                                <p class="review__category" theme="badge small" style\$="--category: [[item.category.id]
];">[[item.category.name]
]</p>
                            </template>
                            <template is="dom-if" if="[[!item.category]
]">
                                <p class="review__category" style="--category: -1;">Undefined</p>
                            </template>
                        </div>
                        <div class="review__date">
                            <h5>Last tasted</h5>
                            <p>[[item.date]
]</p>
                        </div>
                        <vaadin-button on-click="logClick" class="review__edit" theme="tertiary">
                            <iron-icon icon="lumo:edit"></iron-icon><span>[[editButtonText]
]</span>
                        </vaadin-button>
                    </div>
                </template>
            </template>

            <template is="dom-if" if="{{_isEmpty(reviews)}}">
                <div class="reviews__no-matches">No matches</div>
            </template>
        </div>
`;
  }

  static get is() {
      return 'reviews-list'
  }

  logClick() {
	  console.log("Button clicked");
	  console.log(item.name)     
  } 
  _isEmpty(array) {
      return array.length == 0;
  }
}
customElements.define(ReviewListElement.is, ReviewListElement);

The styling is included in the element code using a tag.
Is that the right/best way to style an element you create or should you

create a reviews-list-style.css

and do a

@CssImport(value="./styles/reviews-list-style.css", themeFor="reviews-list") 

I tried this but it doesn’t work for me. Whereas keeping the CSS in the element between the tags does.

In case someone is looking how to do this with Vaadin 14.

Java:

myField.addClassName("edited");

CSS that matches TextField, TextArea, DateField, Select, etc using Lumo theme:

.edited {
    --field-border: inset 0 0 0 1px #CA9605; 
    --field-background: #FEF1CD;
}

.edited::part(checkbox) {
    box-shadow: inset 0 0 0 1px #CA9605; 
    background-color: #FEF1CD;
}