Yes, the template render is quite hard to use in this case.
One solution is to create your own webcomponent that is using the menu item.
Basically a menu that contains only the minimum information (text, icon, children) and create the component.
Here is an example:
// add all the components that are used in the menuicon-lit-renderer
@Uses(MenuBar.class)
@Uses(Icon.class)
@Uses(Button.class)
@JsModule("./src/menuicon-lit-renderer.js")
@Route("template-grid")
public class GridView extends VerticalLayout {
public GridView() {
Grid<String> grid = new Grid<>();
grid.setSelectionMode(Grid.SelectionMode.NONE);
grid.addColumn(TemplateRenderer.<String> of("<menuicon-lit-renderer items=\"[[item.items]
]\"></menuicon-lit-renderer>").withProperty(
"items", c -> {
JsonArray rootMenuItems = Json.createArray();
JsonObject rootMenuItem1 = Json.createObject();
rootMenuItem1.put("icon", "vaadin:menu");
rootMenuItems.set(0, rootMenuItem1);
JsonArray children = Json.createArray();
JsonObject submenu1 = Json.createObject();
submenu1.put("icon", "vaadin:file-text-o");
submenu1.put("text", "Item 1");
children.set(0, submenu1);
JsonObject submenu2 = Json.createObject();
submenu2.put("icon", "vaadin:file-text-o");
submenu2.put("text", "Item 2");
children.set(1, submenu2);
JsonObject submenu3 = Json.createObject();
submenu3.put("icon", "vaadin:file-text-o");
submenu3.put("text", "Item 3");
children.set(2, submenu3);
rootMenuItem1.put("children", children);
return rootMenuItems;
}))
.setSortable(false)
.setWidth("150px")
.setFlexGrow(0);
grid.addComponentColumn(gridItem -> {
MenuBar menuBar = new MenuBar();
menuBar.addThemeVariants(MenuBarVariant.LUMO_ICON);
MenuItem btnMenu = menuBar.addItem(new Icon(VaadinIcon.MENU));
MenuItem firstMenuItem = btnMenu.getSubMenu().addItem(getButton(VaadinIcon.FILE_TEXT_O, "Item 1"));
MenuItem secondMenuItem = btnMenu.getSubMenu().addItem(getButton(VaadinIcon.FILE_TEXT_O, "Item 2"));
MenuItem thirdMenuItem = btnMenu.getSubMenu().addItem(getButton(VaadinIcon.FILE_TEXT_O, "Item 3"));
firstMenuItem.setEnabled(true);
secondMenuItem.setEnabled(true);
thirdMenuItem.setEnabled(true);
return menuBar;
})
.setSortable(false)
.setAutoWidth(true)
.setFlexGrow(0);
add(grid);
List<String> strings = new ArrayList<>();
for (int i = 0; i < 30; i++) {
strings.add(i + "");
}
grid.setItems(strings);
grid.setSizeFull();
setSizeFull();
}
private Component getButton(VaadinIcon icon, String label) {
Button btn = new Button(label);
btn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
btn.setIcon(icon.create());
return btn;
}
}
And the component in javascript: (/src/menuicon-lit-renderer.js)
import { LitElement, html } from 'lit-element';
import '@vaadin/vaadin-menu-bar';
class MenuiconLitRenderer extends LitElement {
static get properties() {
return {
items: { type: Array }
};
}
constructor() {
super();
}
firstUpdated() {
this.items = [];
}
update(changedProperties) {
super.update(changedProperties);
if (changedProperties.has('items')) {
this.menuitems = this.buildMenuicon();
debugger;
}
}
buildMenuicon() {
const menuitems = [];
this.items.forEach(item => {
menuitems.push(this.convertItemToMenu(item));
});
return menuitems;
}
convertItemToMenu(item) {
const children = []
if (item.children) {
item.children.forEach(child => {
children.push(this.convertItemToMenu(child));
});
}
return { component: this.makeIcon(item.icon, item.text), children: children};
}
/*
menu.addEventListener('item-selected', function(e) {
document.querySelector('i').textContent = e.detail.value.text;
});*/
makeIcon(img, txt) {
const item = window.document.createElement('vaadin-context-menu-item');
const icon = window.document.createElement('iron-icon');
icon.setAttribute('icon', img);
item.appendChild(icon);
if (txt) {
item.appendChild(window.document.createTextNode(txt));
}
return item;
}
render() {
return html`<vaadin-menu-bar id="menubar" .items="${this.menuitems}"></vaadin-menu-bar>`;
}
}
customElements.define('menuicon-lit-renderer', MenuiconLitRenderer);
That should give you an idea of the difference of performance.
In my computer, the template render is twice faster than the component renderer but it’s less flexible.