Dynamically Changing Font, Font-Size, Font-Color, and So on in Vaadin Flow Web Apps

Dynamically changing font, font-size, font-color, and so on in Vaadin Flow web apps

The short answer is yes. And this is one of the major changes between Vaadin Platform version 10 and later compared to Vaadin 8 and earlier. In Vaadin Platform theming is not based on SASS anymore.

The reason for this change is because we use web components to create the client "widgets", and web components are based on latest HTML5 standard. They introduce so called shadow DOM and local DOM concepts. I.e. the internals of the web components cannot be styled in global theme. So number of new concepts for theming is needed. Custom properties, themable mixins, etc. We have chapter in our documentation describing this in detail.

Your particular question can be addressed with CSS custom properties. They are basically CSS variables, and have notation --my-property. There is example in documentation how to add custom properties to custom widgets. Values of these custom properties can be defined in global styles and/or run time via Element API of Flow element.getStyle().set("--my-property", "red");.

Also those styles that are exposed naturally can be modified run time using Element API element.getStyle(), like element.getStyle().set("fontWeight", "bold");

So in general Vaadin Flow offers much more features for dynamic styling than Vaadin 8 ever did.

See also: Vaadin Flow/10/11 style component via css

Vaadin Flow TextField: how dynamically change font color?

With the Custom Theme feature, you can add your custom theme @Theme(value = "my-theme"), create a CSS stylesheet file ${project.basedir}/frontend/themes/my-theme/components/vaadin-text-field.css and place the following there:

:host(.my-class-red) [part="input-field"]{
color:red
}

:host(.my-class-blue) [part="input-field"]{
color:blue
}

On the Java side:

TextField name = new TextField("Your name");
name.setLabel("My label");

Button red = new Button("Red", click -> {
name.removeClassName("my-class-blue");
name.addClassName("my-class-red");
});

Button blue = new Button("Blue", click -> {
name.removeClassName("my-class-red");
name.addClassName("my-class-blue");
});

Button reset = new Button("Reset", click -> {
name.removeClassNames("my-class-red", "my-class-blue");
});

add(red, blue, reset);

Is there any way to use font S as standard size in Vaadin Flow 14?

You can override the default Lumo values in a global style sheet. For example, the following will make the fonts consistently smaller:

html {
--lumo-font-size: 1rem;
--lumo-font-size-xxxl: 1.75rem;
--lumo-font-size-xxl: 1.375rem;
--lumo-font-size-xl: 1.125rem;
--lumo-font-size-l: 1rem;
--lumo-font-size-m: 0.875rem;
--lumo-font-size-s: 0.8125rem;
--lumo-font-size-xs: 0.75rem;
--lumo-font-size-xxs: 0.6875rem;
}

For new projects, start.vaadin.com enable the adjustment of the theme downloaded with the starter.

Styling the titles in Vaadin Charts

Theme

The various Theme controlling the look of the charts vary widely in their sizing. The new Valo themes (ValoLightTheme and ValoDarkTheme, matching Vaadin’s new Valo theme) tend to be much larger than the previous default, VaadinTheme (matching Vaadin’s Reindeer theme).

So one easy way to change sizes of chart labels is to switch themes. The theme is not set on the individual chart. Instead, use a global setting affecting all charts within a UI (a web browser’s particular window/tab/portlet). The ChartOptions class has a setTheme method.

ChartOptions.get().setTheme( new VaadinTheme() ); // All charts within a UI share the same Theme object.

Unless you have a specific need, I suggest putting that code in the init method of your UI subclass (such as MyVaadinUI in Vaadin projects created by Maven or the Vaadin Plugin for NetBeans/Eclipse).

Title Object > Style Object

In Vaadin Charts 2, the title and subtitle of the chart are represented by appropriately named objects, Title and Subtitle. Each has an optional Style object. That object has several settings correlating to the usual CSS properties, including:

  • font family
  • font size
  • color

Font Size

So setting the font size is a matter of fetching:

Chart object > Configuration object > Title object > Style object

…and then passing a string value for text size to the setFontSize method.

Seems simple, but there is one catch. The Style object is optional. By default, it does not exist. In other words, the Style object is meant for you and I to override the already-defined internal formatting.

So you must first check for the Style object’s existence, and if null, instantiate it.

Example code using Vaadin 7.3.7 with the fresh new (as of 2014-12) Vaadin Charts 2 in Java 8.

final Configuration configuration = chart.getConfiguration();  // As per usual, interact with the chart via its Configuration object.
Title t = configuration.getTitle(); // Obtain the object representing the title (or Subtitle for subtitle).
if ( t.getStyle() == null ) { // If not yet existing…
t.setStyle( new Style() ); // Instantiate a Style object and install on the Title object.
}
Style st = t.getStyle(); // Obtain the Style object (whether new or pre-existing).
st.setFontSize( "0.5em" ); // Half an em is teeny-tiny, but demonstrates this approach works to change the font size.

Left-Right Alignment

To set the title’s alignment towards the left or right of the chart, no need for the Style object. The Title object itself has a setHorizontalAlignment method. Pass values defined by the HorizontalAlign enum for LEFT, CENTER, RIGHT.

final Configuration configuration = chart.getConfiguration();  // As per usual, interact with the chart via its Configuration object.
Title t = configuration.getTitle(); // Obtain the object representing the title (or Subtitle for subtitle).
t.setHorizontalAlign( HorizontalAlign.LEFT );

Legend

The legend is similar to Title. The Configuration contains a Legend object. The Legend contains a Style object.

Chart object > Configuration object > Legend object > Style object

Legend Item

The items (marker & series name) in a Legend have their own styling. To change the font or font size of those series names, access the items’ Style object. The catch is that there is no layer of "LegendItem" object. Instead of accessing such an object, call the Legend method getItemStyle

Chart object > Configuration object > Legend object > getItemStyle method

Engage Lumo compact mode in Vaadin 13 and later, for smaller size layouts

Add two annotations: @JsModule & @Theme

I found a bit more documentation on this tutorial, Themes and styling in Vaadin, by Jouni Koivuviita on the Vaadin.com site. See Use global variants > Compact.

Add three imports:

import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.lumo.Lumo;

Add two annotations:

@JsModule ("@vaadin/vaadin-lumo-styles/presets/compact.js")
@Theme ( Lumo.class)

To quote the tutorial:

Technically, it adds a <style> element to the page which sets new values for the Lumo sizing and spacing CSS properties. You can view the values from the source code.

For more technical detail, including a list of affected CSS properties, see that first link in tutorial: Compact preset in the Lumo styles demo site. And see the actual code in that second link, the GitHub page: vaadin-lumo-styles/presets/compact.html.

Put that together into a demo class. We are modifying the MainView class generated in a new project by the Vaadin.com project starters page, for Vaadin 14.1.17.

package work.basil.example;

import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.lumo.Lumo;

/**
* The main view contains a button and a click listener.
*/
@JsModule ( "@vaadin/vaadin-lumo-styles/presets/compact.js" )
@Theme ( Lumo.class )
@Route ( "" )
@PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
@CssImport ( "./styles/shared-styles.css" )
@CssImport ( value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field" )
public class MainView extends VerticalLayout
{
enum Animal { DOG, CAT, BIRD, HAMSTER } ;

public MainView ( )
{
// Use TextField for standard text input
TextField textField = new TextField( "Your name" );

// Button click listeners can be defined as lambda expressions
GreetService greetService = new GreetService();
Button button = new Button( "Say hello" ,
e -> Notification.show( greetService.greet( textField.getValue() ) ) );

// Theme variants give you predefined extra styles for components.
// Example: Primary button is more prominent look.
button.addThemeVariants( ButtonVariant.LUMO_PRIMARY );

// You can specify keyboard shortcuts for buttons.
// Example: Pressing enter in this view clicks the Button.
button.addClickShortcut( Key.ENTER );

// Use custom CSS classes to apply styling. This is defined in shared-styles.css.
this.addClassName( "centered-content" );

Select < Animal > animalSelect = new Select <>();
animalSelect.setItems( Animal.values() );
this.add( animalSelect , new TextField( "Bogus1" ) , new TextField( "Bogus2" ) , new TextField( "Bogus3" ) , new TextField( "Bogus4" ) , textField , button );
}
}

Here is the result when running with the embedded Jetty server to Microsoft Edge v 80.0.361.57 client on macOS Mojave 10.14.6.

Screenshot of the above code showing two browser windows, each rendered with and without the two annotations discussed above showing the resulting decrease of both the widgets and their spacing.

I am not clear on whether you need to annotate every one of your UI classes or just the MainView.java. I would guess you must annotate every UI class.

Center widgets within a layout in Vaadin Flow

HorizontalLayout with CSS3 Flexbox

The trusty HorizontalLayout and VerticalLayout classes from olden days are still in Vaadin 14. This pair of classes have been retrofitted to use modern Flexbox technology found in CSS3. See excellent tutorials on Flexbox at CSS-Tricks.com and at Mozilla. CSS3 Flexbox is very close conceptually to the behavior of classic Vaadin HorizontalLayout and VerticalLayout.

In this example below we start with a Vaadin HorizontalLayout.

final public class AuthenticateView extends HorizontalLayout

In the constructor, add your widget to the layout, a LoginForm being the widget in this example.

this.add ( new LoginForm() );

Make the HorizontalLayout to use all the available room with regards to both the width and the height.

this.setSizeFull ();

Set our content in the layout (our LoginForm) to move to the middle horizontally across. The verb “justify” here refers to typographer/designer lingo where justification means alignment to the margin of the page.

this.setJustifyContentMode ( FlexComponent.JustifyContentMode.CENTER );

Lastly, we can specify where our content should appear vertically within our now-very-tall layout. Do we want content at the top, at the bottom, or in the middle?

Notice the difference in syntax here from the Vaadin 8 generation: The term FlexComponent reflects the use of CSS Flexbox.

this.setDefaultVerticalComponentAlignment ( FlexComponent.Alignment.CENTER );

Bonus feature: Let's verify visually the behavior of our HorizontalLayout by coloring its otherwise invisible edges.

this.getStyle ().set ( "border" , "6px dotted DarkOrange" );  // DEBUG - Visually display the  bounds of this layout.

Set this view to be default via the @Route annotation.

@Route ( "" )
final public class AuthenticateView extends HorizontalLayout

When run we find our login form appearing centered within our much bigger web browser window. Notice the orange border showing how our HorizontalLayout has grown to take the entire window.

screenshot of Vaadin LoginForm widget appearing centered within a much bigger web browser window.

For fun, try disabling the various lines of code shown here. Run the app to see the impact the code has on behavior by noticing the placement of the LoginForm and the orange border.

Here is complete class code.

package work.basil.example.ui;

import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.component.login.LoginI18n;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.router.Route;

@Route ( "" )
final public class AuthenticateView extends HorizontalLayout
{
// Constructor
public AuthenticateView ( )
{
super ();

// Widgets
this.add ( new LoginForm () );

// Arrange
this.getStyle ().set ( "border" , "6px dotted DarkOrange" ); // DEBUG - Visually display the bounds of this layout.
this.setSizeFull ();
this.setJustifyContentMode ( FlexComponent.JustifyContentMode.CENTER ); // Put content in the middle horizontally.
this.setDefaultVerticalComponentAlignment ( FlexComponent.Alignment.CENTER ); // Put content in the middle vertically.

}
}

Caveat: This code shown above is nowhere near sufficient for real-world login work. The focus here was on widget layout, not user authentication.



Related Topics



Leave a reply



Submit