3

I use a Vaadin ComboBox to create a dropdown menu, where the user can set a state which will be displayed in another element of the web page. So I really do not need the text-field-part of the ComboBox (the blue line in the image).

This is how it looks like now. The blue line should disappear.

Setting the width manually to 0 in the browser gives the perfect result (no line visible, no text input area available for focus), however I am unable to achieve this using code. Please help me.

I used the example in this tutorial (see vaadin-text-field-styles.css), which changes all ComboBoxes on my web page. The current status looks like this:

//Java-code:
comboBox.addClassName("RemoveTextField");

HTML-stack

/* CSS-File */
:host([class="RemoveTextField"]) [part="input-field"] {
    width: 0px;
}

The CSS rule is not used, I guess the problem is that the .host-selector is not working as I think. As I am a CSS noob please enlighten me how I can use a selector for an element outside the shadow dom.

Mathias
  • 282
  • 1
  • 16

1 Answers1

4

See the end for an alternative solution.

Styling is a bit tricky when you are dealing with nested shadow roots. The part input-field is inside the shadow root of vaadin-text-field, which is inside the shadow root of vaadin-combo-box. As such, it can't be styled from the combo box.

What you can do is create some styles for the text field, like this text-styles.css:

[part="input-field"] {
    width: 0;
}

Next, you can apply this to all text fields by adding this annotation to a Flow view:

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

Now all your input fields have zero width. In order to have it apply only to the text field in your combo box, you can set the theme attribute on it:

myComboBox.getElement().setAttribute("theme", "my-combo");

Then you can update your text-styles.css:

:host([theme="my-combo"]) [part="input-field"] {
    width: 0;
}

So how does this work?

All Vaadin web components implement a ThemableMixin, that does a couple of things:

  1. It enables you to use the themeFor="..." in your @CssImport to inject styles into the shadow root of a Vaadin component.
  2. It propagates any theme attribute you set on the component to any child components inside the shadow root.

In the browser developer tools you will see that the theme attribute has propagated to the vaadin-text-field, and therefore we can use it to limit the scope of our styles. Only the theme attribute is propagated, it will not work with classes, ids etc.

A screenshot of the DOM with the theme attribute propagated from the combo box to the text field

If you were to look into the highlighted style tag, you would also find that the contents of the text-styles.css have been injected there (although the contents might be too long for the devtools to show).

Alternative solution

A combo box might not be the best component for this. Have a look at the MenuBar or ContextMenu.

Erik Lumme
  • 5,202
  • 13
  • 27
  • 2
    Perfect answer, thanks a lot! So "theme" is the way to go to transcent properties through shadow-doms, good to know. And thank you for the alternative solutions. In my case I had to use a ComboBox (otherwise I would have to copy all styling from ComboBox to e.g. ContextMenu), but for other people your suggestions should be the easier solution. – Mathias Jun 10 '21 at 13:29
  • I'm trying to achieve something similar with the vaadin-login-form: https://stackoverflow.com/questions/69841944/vaadin14-login-form-css-selector-for-shadow-root/69845184#69845184 and I've got to the point where I can style all the parts with name "label" using the above method. However, I can not style only the label inside the . In java I'm doing `this.login.getElement().setAttribute("theme", "my-login");` which pushes the theme attribute to `` but not further down the tree. – Sergiu Nov 05 '21 at 05:56