How to center align the text in Vaadin TextField - vaadin

I read the CSS styling section (https://vaadin.com/docs/v14/flow/styling/styling-components) and it mentions that global CSS doesnt affect the 'INPUT" field in the shadow DOM, So styling has to be added to shdaow DOM, But unfortunately no where does it explicitly say HOW to add the styling to the shadow DOM. Note. im using mainly Flow pure java with a bit of CSS.
I tried retrieving the elementt from component then retrieving the shadowRoot, then from root, retrieve the 'input' element to add styling to it, unfortunately that didnt work, shadowroot was null (this code executed from the onAttach() method in the view class)
private void setTextAlignCenterForTextFields(TextField textField) {
//find the internal 'Input' and set the styling to text-align=center, unfortunately
// you cant do that with global css, since the 'input' element is in shadow root
textField.getElement()
.getShadowRoot()
.get()
.getChildren()
.filter( elem -> "INPUT".equalsIgnoreCase(elem.getTag()))
.forEach(inputElem -> inputElem.getStyle().set("text-align", "center"));
}
Any ideas would be appreciated. I'm using Vaadin version 14.5.1.

There's already a theme variant to align the text
centerTextField.addThemeVariants(TextFieldVariant.LUMO_ALIGN_CENTER);
see https://vaadin.com/components/vaadin-text-field/java-examples/theme-variants
As for how to attach CSS to shadow root, basically use themeFor, see https://vaadin.com/docs/v14/flow/styling/importing-style-sheets/#component-styles

You can use CSS to target the value part:
.textfieldClass::part(value) {
text-align: center;
}
This video explains styling CSS parts: https://youtu.be/Y0uxb4ga44Y

Related

Is there any way to use composition to alter the CSS of an web-component with a shadow dom?

my team lead has decided to use LitElement to create framework-agnostic web components, which makes sense, as we're creating a company-wide UI library that would be ideal to be used with Vue2, Vue3, React, Preact, and others.
However, I'm extremely worried about styling. Right now with our current (Vue 2) based UI library, if one of our teams needs to override the internal styling of an element for whatever reason (usually edge cases), one of the things they can do is use CSS Composition in order to do exactly that. Something like:
// in components/my-element.js
class MyElement extends LitElement {
render(){
return html`
<div class="stackui-my-element">
<p class="paragraph">A paragraph</p>
</div>
`;
}
}
customElements.define('my-element', MyElement);
// in app/businessthing.js
import React from 'react';
import {css} from 'styled-components'
const customCSS = css`
.this-thing {
& .stackui-my-element .paragraph {
border: 2px dotted pink;
}
}
`
export default (props) => <div class="this-thing"><my-element /></div>
As far as I can tell, the above code won't work ("My Paragraph" would not be surrounded with pink polka dots) because MyElement has its own shadow dom, and you can't reach in it from without to change the styles of the element.
Is there some sort of exception to the rule, or can you reach inside the shadow dom somehow? Other than losing CSS encapsulation, what are the other effects of disabling the shadow dom?
As you mention, when using Shadow DOM, style encapsulation would prevent users of the component from affecting the styling of the component's internals.
However, there are several ways to achieve what you want with different degrees of flexibility, all of them are part of how the Shadow DOM spec behaves and not Lit-specific, so, you could use this with Vanilla Web Components or components created with other libraries too.
Which of the following ways works better will depend on how strict you want to enforce styling rules for your component.
All the samples below will assume the internal DOM of the component looks like your sample
<div class="stackui-my-element">
<p class="paragraph">A paragraph</p>
</div>
Use custom CSS properties (CSS variables)
This approach is good when you want to limit the customization to only specific parts.
For example, to allow for the user to only be able to change the border for the paragraph, you could use a CSS variable with a fallback for the border in the style for your component's shadow DOM like this:
.paragraph {
border: var(--myel-paragraph-border, 1px solid black);
}
And then, users who wish to customize said border could just change the value for that CSS variable through inline styles or a class.
<style>
.fancy-border {
--myel-paragraph-border: 2px dotted pink;
}
</style>
<my-element class="fancy-border"></my-element>
The biggest limitation of this approach is that you would need to add a CSS variable for every property you wish to allow to be customized.
However, this can be an advantage for some use cases (like say, strict design systems) because it will not allow users to customize anything you don't wish to customize.
Use Shadow Parts
Shadow parts are one of the newer parts of the shadow DOM spec but browser support is pretty good by this point. They allow you to define arbitrary parts of your component you wish to be fully customizable from outside the shadow DOM.
To use them, you need to add the part attribute to the HTML node you wish to define as the part.
<div class="stackui-my-element">
<p part="paragraph" class="paragraph">A paragraph</p>
</div>
And when using the component, add the ::part() selector to the styles so that you can customize that specific part rather than the component host. It works pretty similar to how you would styles things such as a native input placeholder and so on.
<style>
.fancy::part(paragraph) {
/* you can do whatever you want here */
border: 2px dotted pink;
color: blue;
font-style: italic;
}
</style>
<my-element class="fancy"></my-element>
As you can see, shadow parts will allow you to override every style applied to the node, so, you must be careful when to use them as users might end up being able to customize things you don't want them too.
Final notes:
You could also achieve a similar thing using slots, but that might not be an easy change considering the contents of your question.
Here's an article in case you want more info on how styling Shadow DOM from outside the component works. (Disclaimer: I'm the author of that article.)

How to use an Angular Material mat-form-field, but with a normal placeholder

Angular Material form fields are potentially very convenient because they add a bunch of classes to the surrounding element depending on whether the field is selected, empty, filled, etc. I want to use these classes to customize the style of the label and other custom elements placed inside the field container (example: making the label change color when the input is focused).
The problem is that Angular Material also adds a bunch of other properties, styles and elements that I don't want to deal with. Even if I add floatLabel="never" and floatPlaceholder="never", the placeholder is still removed from the input and turned into a label, which is positioned relative to the entire container. If I place other elements inside the mat-form-field element (like a regular label), this messes up the positioning of the placeholder-turned-label, causing it to appear outside the input.
Is there any way I can make Angular Material not turn the placeholder into a label, but just leave it as a normal placeholder?
So I wasn't able to actually fix it properly, but I was able to get around the issue by adding styles to undo the style changes that Angular adds.
mat-form-field.mat-form-field-hide-placeholder .mat-input-element::placeholder{
color: #ccc !important;
-webkit-text-fill-color: #ccc !important;
}
mat-form-field.mat-form-field-hide-placeholder .mat-form-field-label-wrapper{
display: none;
}
It would be nicer if there was a way to not have the .mat-form-field-hide-placeholder class added in the first place, but until someone figures this out this will have to do.
Turns out all you need to do is add appearance="none" to the field tag, e.g.:
<mat-form-field appearance="none">
<input matInput [(ngModel)]="email" placeholder="Email">
</mat-form-field>

Angular material mat menu styling issue

I have two components that using mat menu. I just want to add some extra styling for one mat menu in one component. I have used this css inside the component css
::ng-deep.mat-menu-panel
{
position: fixed !important;
right : 2%;
}
Now the issue is the css is applying to the other component mat menu also.
How can i resolve this?
Add your panel styling to your global style sheet:
.fixed-menu-panel
{
position: fixed !important;
right : 2%;
}
Add the panel style to the mat-menu:
<mat-menu class="fixed-menu-panel">
StackBlitz: https://stackblitz.com/edit/angular-9bheaf?file=index.html
The challenge is that the menu is rendered in an overlay container attached to the parent document and not the button itself... with this in mind, you will need to think about how to grab a reference to that mat-menu-panel and append a class to it to make it unique on menu open.
For example, you could do something like the following to accomplish this.
Create a component method that will receive the templateRef as an argument. It will get the mat-menu-panel using Renderer2 and append a class to it of styled
styleMenu(el) {
const menuPanel = this.ren.parentNode(this.ren.parentNode(el.items.first['_elementRef'].nativeElement));
this.ren.addClass(menuPanel, 'styled')
}
Then in your view, use the (menuOpened) event emitter to call the styleMenu method when the menu opens, and pass the #styledMenu templateRef as an argument.
<button mat-button [matMenuTriggerFor]="styledMenu" (menuOpened)="styleMenu(styledMenu)">styled</button>
<mat-menu #styledMenu="matMenu">
Then your CSS will look like this
::ng-deep .mat-menu-panel.styled
{
position: fixed !important;
right : 2%;
}
This is one approach, you could also roll all of this into a directive and then just apply the directive selector where you need it.
Stackblitz
https://stackblitz.com/edit/angular-5nixtl?embed=1&file=app/menu-overview-example.ts

Custom scrollbars for <vaadin-combo-box> , impossible?

I'm using vaadin-combo-box and I have a problem. I have no clue how to customize look and feel of scrollbars for the dropdown. I read about styling parts and I know how to do it but this seems to be impossible. Cant figure out the way to select #scroller element because it has been design not to be a "part" to style. However that is the only way I can think of to apply custom style to dropdown scrollbars. How can that be accomplished?
Thanks in advance for help.
#Update
Turns out that as of today there is no way of having customized styling on scrollbars for vaadin-combo-box component. Element responsible for scrolling resides inside contents shadow DOM and is inaccessible from outside nor its going to inherit style implemented on the parent part [part="content"]
The dropdown part is called vaadin-combo-box-overlay, see: https://vaadin.com/components/vaadin-combo-box/html-api/elements/Vaadin.ComboBoxOverlayElement And it is available for styling.
This allows to style the dropdown to some extent, but there is additional shadow root, that prevents to apply e.g. ::-webkit-scrollbar styles on #scroller element.
So the last option would be to make a copy of the vaadin-combo-box html file in right place in frontend directory. It happens so that that file will be used instead of the one coming from webjar. Then you can edit that html file directly. Of course this means that if there are changes in future versions of vaadin-combo-box, you need to copy again, re-apply changes

How to set a border on a Vaadin component?

I would like to programmatically set a border around a Form component in Java. How can I do this without having to edit the css style sheet?
You could wrap the form with a Panel component, which has a border defined already. Otherwise, not much alternatives than just using CSS.
One option, if you wish to stay inside the server environment, is to use the CSSInject add-on and add the border using that (you still need to write CSS, but you can do it on the server in a Java file and not inside a regular CSS file).
Vaadin Flow — Style::set to specify CSS
In Vaadin Flow (Vaadin versions 10 and later), you can conveniently set CSS for a widget or layout programmatically. No need to edit separate CSS files, even though styling with CSS files is the recommended way.
On your widget/layout, call getStyle to retrieve the Style object.
On that Style object, call set to pass the name and value of your CSS property.
For example, I find setting a bright colored border on my nested layouts quite helpful for debugging.
myVerticalLayout.getStyle().set( "border" , "6px dotted DarkOrange" ) ;
You can see this in action with this screenshot on my Answer to another Vaadin question here:

Resources