diff --git a/articles/components/context-menu/index.asciidoc b/articles/components/context-menu/index.asciidoc index 022943779a..1b6040542d 100644 --- a/articles/components/context-menu/index.asciidoc +++ b/articles/components/context-menu/index.asciidoc @@ -191,6 +191,39 @@ include::{root}/frontend/demo/component/contextmenu/react/context-menu-presentat endif::[] -- +== Styling Menu Items + +Individual menu items can be styled by [since:com.vaadin:vaadin@V24.3]#applying custom class names# to them, and writing CSS style blocks targeting those class names. + +[.example] +-- + +ifdef::lit[] +[source,typescript] +---- +include::{root}/frontend/demo/component/contextmenu/context-menu-classname.ts[render,tag=snippet,indent=0,group=TypeScript] +---- +endif::[] + +ifdef::flow[] +[source,java] +---- +include::{root}/src/main/java/com/vaadin/demo/component/contextmenu/ContextMenuClassname.java[render,tags=snippet,indent=0,group=Java] +---- +endif::[] + +ifdef::react[] +[source,tsx] +---- +include::{root}/frontend/demo/component/contextmenu/react/context-menu-classname.tsx[render,tags=snippet,indent=0,group=React] +---- +endif::[] +-- + +.Use theme names instead of class names in V24.2 and older +[NOTE] +In versions prior to 24.3, theme names must be used instead (`theme` property / `addThemeNames` Java method). The CSS syntax for targeting a theme name is `[theme~="custom-theme"]` + == Disabled Menu Items You can disable menu items to show that they are unavailable. diff --git a/frontend/demo/component/contextmenu/context-menu-classname.ts b/frontend/demo/component/contextmenu/context-menu-classname.ts new file mode 100644 index 0000000000..be0c33612b --- /dev/null +++ b/frontend/demo/component/contextmenu/context-menu-classname.ts @@ -0,0 +1,34 @@ +import 'Frontend/demo/init'; // hidden-source-line +import { html, LitElement } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import '@vaadin/button'; +import '@vaadin/context-menu'; +import type { ContextMenuItem } from '@vaadin/context-menu'; +import { applyTheme } from 'Frontend/generated/theme'; + +@customElement('context-menu-classname') +export class Example extends LitElement { + protected override createRenderRoot() { + const root = super.createRenderRoot(); + // Apply custom theme (only supported if your app uses one) + applyTheme(root); + return root; + } + + // tag::snippet[] + @state() + private accessor items: ContextMenuItem[] = [ + { text: 'Share' }, + { text: 'Duplicate' }, + { text: 'Delete', className: 'text-error' }, + ]; + // end::snippet[] + + protected override render() { + return html` + + Actions + + `; + } +} diff --git a/frontend/demo/component/contextmenu/react/context-menu-classname.tsx b/frontend/demo/component/contextmenu/react/context-menu-classname.tsx new file mode 100644 index 0000000000..466a219a5b --- /dev/null +++ b/frontend/demo/component/contextmenu/react/context-menu-classname.tsx @@ -0,0 +1,22 @@ +import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-line +import React, { useState } from 'react'; +import { Button } from '@hilla/react-components/Button.js'; +import { ContextMenu, type ContextMenuItem } from '@hilla/react-components/ContextMenu.js'; + +function Example() { + // tag::snippet[] + const [items] = useState([ + { text: 'Share' }, + { text: 'Duplicate' }, + { text: 'Delete', className: 'text-error' }, + ]); + // end::snippet[] + + return ( + + + + ); +} + +export default reactExample(Example); // hidden-source-line diff --git a/src/main/java/com/vaadin/demo/component/contextmenu/ContextMenuClassname.java b/src/main/java/com/vaadin/demo/component/contextmenu/ContextMenuClassname.java new file mode 100644 index 0000000000..6313430217 --- /dev/null +++ b/src/main/java/com/vaadin/demo/component/contextmenu/ContextMenuClassname.java @@ -0,0 +1,32 @@ +package com.vaadin.demo.component.contextmenu; + +import com.vaadin.demo.DemoExporter; // hidden-source-line +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.contextmenu.ContextMenu; +import com.vaadin.flow.component.contextmenu.MenuItem; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.router.Route; + +@Route("context-menu-classname") +public class ContextMenuClassname extends Div { + + public ContextMenuClassname() { + Button button = new Button("Actions"); + ContextMenu menu = new ContextMenu(); + + menu.setTarget(button); + menu.setOpenOnClick(true); + + menu.addItem("Share"); + menu.addItem("Duplicate"); + // tag::snippet[] + MenuItem item = menu.addItem("Delete"); + item.setClassName("text-error"); + // end::snippet[] + + add(button); + } + + public static class Exporter extends DemoExporter { // hidden-source-line + } // hidden-source-line +}