4

I would like to style Vaadin Upload component (vaadin-upload) by changing appearance of the elements in file list, e.g. hide commands buttons (start, remove, retry). The file list contains vaadin-upload-file elements.

For now I'm only able to customize vaadin-upload itself by adding custom theme to it and importing proper css - just like in this example: https://cookbook.vaadin.com/large-upload-area.

@CssImport(value = "./styles/custom-upload.css", themeFor = "vaadin-upload")
public class MainView extends VerticalLayout implements HasUrlParameter<String> {

    public MainView() {
        Upload upload = new Upload();
        upload.getElement().getThemeList().add("custom-upload");
        add(upload);
    }
}

custom-upload.css:

:host([theme~="custom-upload"]) {
  border: 0;
}

:host([theme~="custom-upload"]) [part="commands"] {
  display: none;
}

Simplified DOM:

<vaadin-upload theme="custom-upload" target="VAADIN/dynamic/resource/1/70860bf9-21c4-474e-9418-fd5516c28736/upload">
    #shadow-root
        <div part="primary-buttons">...</div>
        <slot name="file-list">
            <div id="fileList" part="file-list">
                <vaadin-upload-file>...</vaadin-upload-file>
            </div>
        </slot>
        ...
</vaadin-upload>

Documentation states that:

Is there a way to attach custom theme to vaadin-upload-file component?

kamillo
  • 131
  • 7

2 Answers2

7

Yes, you just need a separate style module targeting the vaadin-upload-file component, which is doable using the @CssImport annotation. For example,

@CssImport(value = "./styles/custom-upload-file.css", themeFor = "vaadin-upload-file")

Then the custom CSS can be added to {project_root}/frontend/styles/custom-upload-file.css.

EDIT: unlike other Vaadin components, a theme name that is assigned to vaadin-upload doesn't (unfortunately) get propagated down to vaadin-upload-file. Thus, one cannot rely on the theme attribute in order to selectively style some vaadin-upload-file components within the same application.

If selective styling is necessary, a hacky workaround is possible by making a JavaScript call that adds a classname to the vaadin-upload-file component. Such call would, however, only work after the vaadin-upload-file is rendered in the DOM (which typically occurs upon the success of a file upload). Hence, the JS call should be made from within an upload-success listener.

Here's this workaround in action used to selectively hide the clear button of the vaadin-upload-file:

@Route
@CssImport(value = "./styles/vaadin-upload-styles.css", themeFor = "vaadin-upload-file")
public class MainView extends VerticalLayout {

    public MainView() {

        MemoryBuffer buffer = new MemoryBuffer();
        Upload upload = new Upload(buffer);
        upload.addSucceededListener(e -> {
            upload.getElement()
                    .executeJs("this.shadowRoot.querySelector('vaadin-upload-file').className = 'hidden-clear'");
        });

        Button showClear = new Button("Show clear button", e -> upload.getElement()
                .executeJs("this.shadowRoot.querySelector('vaadin-upload-file').className = ''"));

        add(upload, showClear);
    }

}

Then in vaadin-upload-styles.css, one can do something like:

:host(.hidden-clear) [part~=clear-button] {
    display: none;
}
Tarek Oraby
  • 1,199
  • 6
  • 11
  • Thanks, but how to add this theme to `vaadin-upload-file`, i.e. how can I get this object to call `getThemeList().add("custom-upload-file")` on it? – kamillo Nov 09 '21 at 14:34
  • 2
    @kamillo Unfortunately theme propagation is not consistently implemented in all components, and vaadin-upload is one component where theme propagation does not work. Furthermore, there is no API to access the file upload element directly. I'm afraid currently you can only theme upload files for all uploads. You might want to raise an issue here: https://github.com/vaadin/web-components. – Sascha Ißbrücker Nov 09 '21 at 15:15
  • Thank for explanation @SaschaIßbrücker. After all I think I'm ok with styling all upload files components the same way. – kamillo Nov 09 '21 at 15:41
  • @kamillo FYI, a hacky workaround is possible via making a JS call that adds a classname to the `vaadin-upload-file` component. This workaround is demoed here: https://github.com/tarekoraby/upload-demo/blob/main/src/main/java/org/vaadin/example/MainView.java – Tarek Oraby Nov 10 '21 at 11:01
  • I edited the answer to mention this workaround. – Tarek Oraby Nov 10 '21 at 11:16
  • @TarekOraby hi, how to do with Vaadin 23 ? i am try but nothing, vaadin can`t read @CssImport. – 0x52 Jul 24 '22 at 17:31
  • @TarekOraby I resolved it, create a components dir inside my themes dir, but i am not using the @CssImport, and use ```@import url('components/vaadin-upload-file.css');``` in main styles.css – 0x52 Jul 24 '22 at 18:05
2

To modify the style in a Vaadin Web Component extending ThemableMixin, you can

  • do what Tarek said, or
  • create a custom theme with a file named vaadin-upload-file.css in the components folder. Read more here.

Either way, you need to understand that ThemeList#add(String) is just appending the argument to the theme attribute on the client side. So, you just need to handle the new theme in CSS, for example:

:host([theme~="prettypink"]) [part="done-icon"]::before {
    color: #ff31f1;
}

Here are the default Lumo styles for vaadin-upload and vaadin-upload-file.

Oliver
  • 1,465
  • 4
  • 17