How to style vaadin-upload-file component inside Vaadin Upload

775 views Asked by At

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?

2

There are 2 answers

7
Tarek Oraby On BEST ANSWER

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;
}
0
Oliver On

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.