Vaadin-Tutorials
CSS Selectors
The following CSS selectors can be used in stylesheets to target the various parts and states of the component. See the Styling documentation for more details on how to style components.
-------------------------------------------------------------------------------------------------------
Accordion
@Route("accordion-basic")
public class AccordionBasic extends Div
{
//Creating a constructor
public AccordionBasic()
{
Accordion accordion = new Accordion();
Span name = new Span("Deepesh Dhaundiyal");
Span email = new Span("deepeshd@kognosdata.com");
Span phone = new Span("+91 798-2600-xxx");
VerticalLayout info = new VerticalLayout(name,email, phone);
info.setSpacing(false);
info.setPadding(false);
accordion.add("Personal Details" , info);
Span houseAddress = new Span("D-1 A block Janakouri");
Span picode = new Span("110010");
Span city = new Span("Delhi");
VerticalLayout buildingAddressLayout = new VerticalLayout();
buildingAddressLayout.setPadding(false);
buildingAddressLayout.setSpacing(false);
buildingAddressLayout.add(houseAddress, picode, city);
accordion.add("Office Building Address" , buildingAddressLayout);
add(accordion);
}
}
Anatomy
Accordion consists of stacked panels, each composed of two parts: a summary and a content area. Only one panel can be expanded at a time. Use the Details component to allow multiple, simultaneously expanded sections.
Summary
The summary is the part that’s always visible, and typically describes the content, for example, with a title. Clicking on the summary toggles the content area’s visibility.
The summary supports rich content and can contain any component. This can be utilized, for example, to display the status of the corresponding content.
Reverse Accordion
@Route("")
public class AccordionReversePannel extends Div
{
public AccordionReversePannel()
{
Accordion accordion = new Accordion();
Span name = new Span("Deep");
Span company = new Span("KognosData");
Span email = new Span("mymailid@company.com");
VerticalLayout personalDetailsLayout = new VerticalLayout(name,company,email);
personalDetailsLayout.setSpacing(false);
personalDetailsLayout.setPadding(false);
AccordionPanel personalDetailsPannel = accordion.add("Personal Information",personalDetailsLayout);
personalDetailsPannel.addThemeVariants(DetailsVariant.REVERSE);
Span street = new Span ("Street no. 1");
Span pincode = new Span("110011");
Span city = new Span("Delhi");
VerticalLayout buildingAddressLayout = new VerticalLayout();
buildingAddressLayout.setPadding(false);
buildingAddressLayout.setSpacing(false);
buildingAddressLayout.add(street, pincode, city);
AccordionPanel buildingAddressPanel = accordion.add("Building Address", buildingAddressLayout);
buildingAddressPanel.addThemeVariants(DetailsVariant.REVERSE);
add(accordion);
}
}
--------------------------------------------------------------
https://vaadin.com/docs/latest/components/app-layout
package com.example.application.views.list.AppLayout;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;
@Route("")
public class Basic extends AppLayout
{
public Basic()
{
DrawerToggle toggle = new DrawerToggle();
H1 tittle = new H1("My App");
tittle.getStyle().set("font-size","var(--lumo-font-size-l)").set("margin","0");
Tabs tabs = getTabs();
addToDrawer(tabs);
addToNavbar(toggle,tittle);
}
private Tabs getTabs()
{
Tabs tabs = new Tabs();
tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));
tabs.setOrientation(Tabs.Orientation.VERTICAL);
return tabs;
}
private Component createTab(VaadinIcon viewIcon, String viewName)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("margin-inline-start", "var(--lumo-space-xs)")
.set("padding", "var(--lumo-space-xs)");
RouterLink link = new RouterLink();
link.add(icon, new Span(viewName));
// Demo has no routes
// link.setRoute(viewClass.java);
link.setTabIndex(-1);
return new Tab(link);
}
}
Navigation Bar Placement || Navbar Placement
The navbar can be located on top or to the side of the drawer.
When put on top, the navbar is typically used as an application header. Application headers contain, for example, the application’s name and branding, as well as actions that apply to the entire application, such as notifications, settings, etc.
package com.example.application.views.list.AppLayout;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.RouterLink;
public class NavBarPlacement extends AppLayout
{
public NavBarPlacement()
{
DrawerToggle drawerToggle = new DrawerToggle();
H1 tittle = new H1("MyApp");
tittle.getStyle().set("font-size","var(--lumo-font-size-l)").set("margin","0");
Tabs tabs = getTabs();
addToDrawer(tabs);
addToNavbar(drawerToggle, tittle);
}
private Tabs getTabs() {
Tabs tabs = new Tabs();
tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));
tabs.setOrientation(Tabs.Orientation.VERTICAL);
return tabs;
}
private Component createTab(VaadinIcon viewIcon, String nameView)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("margin-inline-start", "var(--lumo-space-xs)")
.set("padding", "var(--lumo-space-xs)");
RouterLink link = new RouterLink();
link.add(icon, new Span(nameView));
link.setTabIndex(-1);
return new Tab(link);
}
}
When placed to the side, the navbar is often seen as a view header, housing the view’s title, and actions and secondary navigation that relate only to the current view.
package com.example.application.views.list.AppLayout;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;
@Route("")
public class NavBarPlacementSide extends AppLayout
{
public NavBarPlacementSide()
{
DrawerToggle toggle = new DrawerToggle();
H1 title = new H1("Dashboard");
title.getStyle().set("font-size", "var(--lumo-font-size-l)")
.set("margin", "0");
Tabs tabs = getTabs();
addToDrawer(tabs);
addToNavbar(toggle, title);
setPrimarySection(Section.DRAWER);
}
private Tabs getTabs()
{
Tabs tabs = new Tabs();
tabs.add(createTab(VaadinIcon.DASHBOARD, "Dashboard"),
createTab(VaadinIcon.CART, "Orders"),
createTab(VaadinIcon.USER_HEART, "Customers"),
createTab(VaadinIcon.PACKAGE, "Products"),
createTab(VaadinIcon.RECORDS, "Documents"),
createTab(VaadinIcon.LIST, "Tasks"),
createTab(VaadinIcon.CHART, "Analytics"));
tabs.setOrientation(Tabs.Orientation.VERTICAL);
return tabs;
}
private Tab createTab(VaadinIcon viewIcon, String viewName)
{
Icon icon = viewIcon.create();
icon.getStyle().set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("padding", "var(--lumo-space-xs)");
RouterLink link = new RouterLink();
link.add(icon,new Span(viewName));
link.setTabIndex(-1);
return new Tab(link);
}
}
Auto height
When the App Layout has an undefined/auto height, which is the default behavior, the <body> element is the scrolling container for the content inside the layout.
package com.example.application.views.list.AppLayout;
import java.util.List;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.html.H1;
import com.vaadin.demo.domain.Person;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.router.Route;
import com.vaadin.demo.domain.DataService;
@Route("")
// tag::snippet[]
public class AppLayoutHeightAuto extends AppLayout {
public AppLayoutHeightAuto() {
H1 title = new H1("MyApp");
title.getStyle().set("font-size", "var(--lumo-font-size-l)")
.set("margin", "var(--lumo-space-m)");
addToNavbar(title);
Grid<Person> grid = new Grid<>(Person.class, false);
grid.addColumn(Person::getFirstName).setHeader("First name");
grid.addColumn(Person::getLastName).setHeader("Last name");
grid.addColumn(Person::getEmail).setHeader("Email");
grid.addColumn(Person::getProfession).setHeader("Profession");
List<Person> people = DataService.getPeople(20);
grid.setItems(people);
grid.setAllRowsVisible(true);
setContent(grid);
}
// end::snippet[]
// tag::snippet[]
}
// end::snippet[]
Bottom Navbar on Small Touchscreens
When the navbar is used for navigation, the touch-optimized navbar slot can be used to provide a separate version of the navigation at the bottom of the UI, optimized for mobile phones.
https://vaadin.com/docs/latest/components/app-layout/#navbar-placement
--------------------------------------------------------------------
package com.example.application.views.list.button;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.router.Route;
@Route
public class Basic extends Div
{
int counter = 0 ;
public Basic()
{
Button button = new Button();
Paragraph info = new Paragraph("Button");
button.addClickListener(buttonClickEvent -> {
counter += 1;
info.setText(infoText());
});
HorizontalLayout horizontalLayout = new HorizontalLayout(button , info);
horizontalLayout.setAlignItems(FlexComponent.Alignment.BASELINE);
add(horizontalLayout);
}
private String infoText()
{
return String.format("Clicked %d times" , counter);
}
}
--------------------------------------------------------------------
Keeping two buttons side by side || next to each other
Button button = new Button("Click me");
DatePicker datePicker = new DatePicker("Please select a Date!");
HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);
add(horizontalLayout);
Alignment
HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);
horizontalLayout.setDefaultVerticalComponentAlignment(Alignment.AUTO);
add(horizontalLayout);
Button Event Handling || Adding click event
Button button = new Button("Click me");
DatePicker datePicker = new DatePicker("Please select a Date!");
HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);
horizontalLayout.setDefaultVerticalComponentAlignment(Alignment.END);
add(horizontalLayout);
button.addClickListener(click -> add(new Paragraph("Clicked: " + datePicker.getValue())));
TextField filterText = new TextField(); private HorizontalLayout getToolbar() {
filterText.setPlaceholder("Filter by name...");
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);
Button addContactButton = new Button("Add contact");
add(addContactButton, filterText);
//Event
var toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}
package com.example.application.views.list;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
@PageTitle("MyFirstPage")
public class MainView extends VerticalLayout
{
public MainView()
{
Button button = new Button("Search");
TextField textField = new TextField("Enter text to be search...");
// DatePicker datePicker = new DatePicker("Please select a Date!");
//HorizontalLayout horizontalLayout = new HorizontalLayout(button,datePicker);
HorizontalLayout horizontalLayout = new HorizontalLayout(textField,button);
VerticalLayout verticalLayout = new VerticalLayout(textField,button);
verticalLayout.setDefaultHorizontalComponentAlignment(Alignment.BASELINE);
add(verticalLayout);
button.addClickListener(click -> add(new Paragraph("Searched for : " + textField.getValue())));
}
}
package com.example.application.views.list;
import com.example.application.data.entity.Contact;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
@PageTitle("Contacts || Vaadin CRM")
@Route("")
public class ContactList extends VerticalLayout
{
Grid<Contact> grid = new Grid<>(Contact.class);
TextField textField = new TextField();
//Loading a constructor for class ContactList
public ContactList()
{
addClassName("contact-list");
setSizeFull();
//Calling a configureGrid-method to configure grid for our contact-list page.
configureGrid();
//Adding toolbar and grid to our page
add(
getToolbar(),
grid
);
}
private Component getToolbar()
{
textField.setPlaceholder("Search by name...");
textField.setClearButtonVisible(true);
//Lazy bcz we want to fetch result from DB once user complete typing the word "deep" not only for 1-by-1 letter "d,e,e,p"
textField.setValueChangeMode(ValueChangeMode.LAZY);
textField.setValueChangeMode(ValueChangeMode.LAZY);
//textField.addValueChangeListener(e -> updateList());
//Adding a button to our toolbar to perform some action.
Button button = new Button("SEARCH!");
//Now setting horizontal layout for button and textField in our page
HorizontalLayout toolbar = new HorizontalLayout(textField, button);
//Setting class name to apply CSS later on
toolbar.addClassName("toolbar");
return toolbar;
}
public void configureGrid()
{
//Adding class name for CSS file
grid.addClassName("contact-grid");
grid.setSizeFull();
grid.setColumns("firstName","lastName","email");
grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
}
}
//Create Button object for createButtonLayout-method
Button save = new Button("Save Contact");
Button delete = new Button("Delete Contact");
Button cancel = new Button("Cancel Contact");
private Component createButtonLayout()
{
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
cancel.addClickShortcut(Key.ESCAPE);
return new HorizontalLayout(save, delete, cancel);
}
BUTOONS ARE SHOWN BELOW IN CONTACT FORM FOR REFERENCE IMAGE
@PageTitle("Contacts || Vaadin CRM")
@Route("")
public class ContactList extends VerticalLayout
{
Grid<Contact> grid = new Grid<>(Contact.class);
TextField textField = new TextField();
ContactFormList form;
//Loading a constructor for class ContactList
public ContactList()
{
addClassName("contact-list");
setSizeFull();
//Calling a configureGrid-method to configure grid for our contact-list page.
configureGrid();
configureForm();
//Adding toolbar and grid to our page
add(
getToolbar(),
getContent()
);
}
private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2,grid);
content.setFlexGrow(1,form);
content.addClassName("content");
content.setSizeFull();
return content;
}
private void configureForm() {
form = new ContactFormList(Collections.emptyList(), Collections.emptyList());
form.setWidth("25em");
}
private Component getToolbar()
{
textField.setPlaceholder("Search by name...");
textField.setClearButtonVisible(true);
//Lazy bcz we want to fetch result from DB once user complete typing the word "deep" not only for 1-by-1 letter "d,e,e,p"
textField.setValueChangeMode(ValueChangeMode.LAZY);
textField.setValueChangeMode(ValueChangeMode.LAZY);
//textField.addValueChangeListener(e -> updateList());
//Adding a button to our toolbar to perform some action.
Button button = new Button("SEARCH!");
//Now setting horizontal layout for button and textField in our page
HorizontalLayout toolbar = new HorizontalLayout(textField, button);
//Setting class name to apply CSS later on
toolbar.addClassName("toolbar");
return toolbar;
}
public void configureGrid()
{
//Adding class name for CSS file
grid.addClassName("contact-grid");
grid.setSizeFull();
grid.setColumns("firstName","lastName","email");
grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
}
}
package com.example.application.views.list;
import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
import com.vaadin.flow.component.Component;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import java.util.List;
public class ContactFormList extends FormLayout
{
TextField firstName = new TextField("First Name");
TextField lastName = new TextField("Last Name");
TextField email = new TextField("Email-ID");
//To be understood...???????
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");
//Create Button object for createButtonLayout-method
Button save = new Button("Save Contact");
Button delete = new Button("Delete Contact");
Button cancel = new Button("Cancel Contact");
//Loading constructor...
public ContactFormList(List<Company> companies, List <Status> statuses)
{
addClassName("contact-form-list");
company.setItems(companies);
//To be understood...???????
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status :: getName);
add(
firstName, lastName, email, company, status,
createButtonLayout()
);
}
private Component createButtonLayout()
{
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
cancel.addClickShortcut(Key.ESCAPE);
return new HorizontalLayout(save, delete, cancel);
}
}
Step 1: Download a Vaadin Project
Unpack the downloaded zip into a folder on your computer, and import the project in the IDE of your choice. (Alternatively, open the project in an online IDE).
Open src/main/java/org/vaadin/example/MainView.java
Replace the code in Main-View with the code below:-
//This@Routeannotation makes the view accessible to the end user, in this case, using the empty `` route.@Route("") 1 public class MainView extends VerticalLayout { 2 //As the theMainViewclass extendsVerticalLayout, components added to it will be ordered //vertically.
public MainView() { VerticalLayout todosList = new VerticalLayout(); 3//todosListis a vertical layout that displays a list of the tasks along with checkboxes.
TextField taskField = new TextField(); 4 //is a text input field to enter the description of new tasks. Button addButton = new Button("Add"); 5 //is a button for adding a new task. addButton.addClickListener(click -> { 6 //in the listener for the button click, first create a new checkbox with the value from thetaskFieldas its label, then add the checkbox to thetodosList. Checkbox checkbox = new Checkbox(taskField.getValue()); todosList.add(checkbox); }); addButton.addClickShortcut(Key.ENTER); 7 Set a shortcut for theaddButtoncomponent when the key is pressed. add( 8 Calladd()on theVerticalLayoutto display the components vertically. Notice thattaskFieldandaddButtonare in aHorizontalLayout, which puts them next to each other.new H1("Vaadin Todo"), todosList, new HorizontalLayout( taskField, addButton ) ); } }
package com.example.application.views.list;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
@Route("")
public class MainView extends VerticalLayout {
public MainView() {
VerticalLayout todosList = new VerticalLayout();
TextField taskField = new TextField();
Button addButton = new Button("Add");
addButton.addClickListener(click -> {
Checkbox checkbox = new Checkbox(taskField.getValue());
todosList.add(checkbox);
});
addButton.addClickShortcut(Key.ENTER);
add(
new H1("Create your task list"),
todosList,
new HorizontalLayout(
taskField,
addButton
)
);
}
}
Creating Components Using Composition
Vaadin Flow is a component-based framework. You’ve already worked with several components, like Grid, TextField, and VerticalLayout. But, the real power of the component-based architecture is in the ability to create your own components.
Instead of building an entire view in a single class, your view can be composed of smaller components that each handle different parts of the view. The advantage of this approach is that individual components are easier to understand and test. The top-level view is used mainly to orchestrate the components.
Creating a Form Component
The form component you will create has:
Text fields for the first and last name.
An email field.
Two select fields: one to select the company and the other to select the contact status.
Create a new file, ContactForm.java, in the com.example.application.views.list package. If you are using IntelliJ, copy the code below and paste it into the views package. IntelliJ will automatically create the file.
package com.example.application.views.list;
import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import java.util.List;
@Route("")
//public class ContactForm extends VerticalLayout {
//public class ContactForm extends HorizontalLayout {
public class ContactForm extends FormLayout {
//ContactForm extends FormLayout, a responsive
// layout that shows form fields in 1 or 2 columns
// depending on viewport width.
//Creating all the UI components as fields required in the Form component.
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
//Gives the component a CSS class name,
// so you can style it later.
public ContactForm(List<Company> companies, List<Status> statuses) {
addClassName("contact-form");
company.setItems(companies);
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status::getName);
//Adds all the UI components to the layout.
//The buttons require a bit of extra configuration.
// Create and call a new method, createButtonsLayout().
add(firstName,
lastName,
email,
company,
status,
createButtonsLayout());
}
/* private HorizontalLayout createButtonsLayout1() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
return new HorizontalLayout(save, delete, close);
}*/
private VerticalLayout createButtonsLayout()
{
//Makes the buttons visually distinct from
// each other using built-in theme variants.
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
//Defines keyboard shortcuts:
//Enter to save and Escape to close the editor.
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
//Returns a VerticalLayout containing
//the buttons to place them next to each other.
return new VerticalLayout(save, delete, close);
}
}
CREATING A FROM COMPONENT:-
ContactForm.java class
package com.example.application.views.list;
import com.example.application.data.entity.Company;
import com.example.application.data.entity.Status;
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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;
import java.util.List;
public class ContactForm extends FormLayout {
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
public ContactForm(List<Company> companies, List<Status> statuses) {
addClassName("contact-form");
company.setItems(companies);
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status::getName);
add(firstName,
lastName,
email,
company,
status,
createButtonsLayout());
}
private HorizontalLayout createButtonsLayout() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
return new HorizontalLayout(save, delete, close);
}
}
MainView.java class :-
package com.example.application.views.list;
import com.example.application.data.entity.Contact;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.Collections;
@Route("")
@PageTitle("Contacts | Vaadin CRM")
public class ListView extends VerticalLayout {
Grid<Contact> grid = new Grid<>(Contact.class);
TextField filterText = new TextField();
ContactForm form;
HorizontalLayout horizontalLayout = new HorizontalLayout();
public ListView() {
addClassName("list-view");
setSizeUndefined();
configureGrid();
configureForm();
add(getToolbar(), getContent());
}
private void configureGrid() {
grid.addClassNames("contact-grid");
grid.setSizeFull();
grid.setColumns("firstName", "lastName", "email");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
horizontalLayout.add(grid);
}
private HorizontalLayout getToolbar() {
filterText.setPlaceholder("Filter by name...");
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);
Button addContactButton = new Button("Add contact");
add(addContactButton, filterText);
//Event
var toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}
private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.addClassNames("contact-form");
content.addClassNames("list-view");
content.setSizeFull();
content.add(grid,form);
return content;
}
private void configureForm() {
form = new ContactForm(Collections.emptyList(), Collections.emptyList());
form.setWidth("25em");
}
}
Layouts
Layouts decide how components are positioned in the browser window. The most common layout components are HorizontalLayout, VerticalLayout, and Div. The first two set the content orientation as horizontal or vertical, whereas Div lets you control the positioning with CSS
HorizontalLayout and VerticalLayout have methods to align items on both the primary and the cross axis. For example, if you want all components, regardless of their height, to be aligned with the bottom of a HorizontalLayout, you can set the default alignment to Alignment.END.
Using this example, and the add() method to add components to layouts, you would do something like this:
UI Events
You can add functionality to your application by listening to events. Events can include button clicks and value changes from select components.
This example adds the text "Clicked!" to the layout when the button is clicked:
HTML
One unique Vaadin Flow feature is that you can build web applications entirely in Java, eliminating the need to write common HTML. This higher level of abstraction makes development more productive and debugging easier.
Vaadin does support HTML templates and customizing the code that runs in the browser. However, you don’t usually have to worry about this.
The Contact List View
The first view is the Contact list view. You can see how it looks in the screenshot here. It lists all contacts. Users can search, add, edit, and delete contacts in this view.
You’ll focus initially only on the list view. You’ll add a layout containing the header and sidebar later on the "Navigation & App Layout" part.
On this part and the next, you’ll create the required layouts and components for the view. Then, on the part that follows, you’ll create a service class for accessing the backend and populating the view with data.
Flow CRM Tutorial
This project can be used as a starting point to create your own Vaadin application with Spring Boot. It contains all the necessary configuration and some placeholder files to get you started.
Running the application
The project is a standard Maven project. To run it from the command line, type mvnw (Windows), or ./mvnw (Mac & Linux), then open http://localhost:8080 in your browser.
You can also import the project to your IDE of choice as you would with any Maven project. Read more on how to import Vaadin projects to different IDEs (Eclipse, IntelliJ IDEA, NetBeans, and VS Code).
Deploying to Production
To create a production build, call mvnw clean package -Pproduction (Windows), or ./mvnw clean package -Pproduction (Mac & Linux). This will build a JAR file with all the dependencies and front-end resources, ready to be deployed. The file can be found in the target folder after the build completes.
Once the JAR file is built, you can run it using java -jar target/flowcrmtutorial-1.0-SNAPSHOT.jar
Project structure
MainLayout.javainsrc/main/javacontains the navigation setup (i.e., the side/top bar and the main menu). This setup uses App Layout.viewspackage insrc/main/javacontains the server-side Java views of your application.viewsfolder infrontend/contains the client-side JavaScript views of your application.themesfolder infrontend/contains the custom CSS styles.
Useful links
- Read the documentation at vaadin.com/docs.
- Follow the tutorial at vaadin.com/docs/latest/tutorial/overview.
- Create new projects at start.vaadin.com.
- Search UI components and their usage examples at vaadin.com/docs/latest/components.
- View use case applications that demonstrate Vaadin capabilities at vaadin.com/examples-and-demos.
- Build any UI without custom CSS by discovering Vaadin's set of CSS utility classes.
- Find a collection of solutions to common use cases at cookbook.vaadin.com.
- Find add-ons at vaadin.com/directory.
- Ask questions on Stack Overflow or join our Discord channel.
- Report issues, create pull requests in GitHub.
Deploying using Docker
To build the Dockerized version of the project, run
mvn clean package -Pproduction
docker build . -t flowcrmtutorial:latest
Once the Docker image is correctly built, you can test it locally using
docker run -p 8080:8080 flowcrmtutorial:latest








Comments
Post a Comment