3

I have been wasted hours and days trying to style the Vaadin Upload component. The goal is simple:

  • sometimes I need the component to show the uploaded file using its built-in file list with allows delete.
  • other times, I want to hide this list because I have another component such as Grid to show the file details.

Now comes the problem, I can never get it to consistently work using @CssImport with themeFor=vaadin-upload and themeFor=vaadin-upload-file. Vaadin seems to compile the shadow dom and the final result varies, it mixes up the two options and whichever comes last gets applied.

I then thought maybe because the @CssImport is in the @Route component. So, I created two custom upload components that extended the vaadin-upload component with the difference being the different @CssImport (see below). That (frustratingly) still doesn't work. I inspect the document and found that the inside the shadow-dom contains both even though I never use both on the same page.

@CssImport(value = "./css/vaadin-upload-show.css", themeFor = "vaadin-upload")
public class UploadShowFiles extends Upload {

    private static final long serialVersionUID = -9198630843136885092L;

    public UploadShowFiles(Receiver receiver) {
        super(receiver);
    }

}

@CssImport(value = "./css/vaadin-upload-hidefile.css", themeFor = "vaadin-upload")
public class UploadHideFiles extends Upload {

    private static final long serialVersionUID = 2344860066834705807L;

    public UploadHideFiles(Receiver receiver) {
        super(receiver);
        setClassName("hide-upload");
    }

}

The css below will appear in the shadow dom. I expect only display: none or otherwise, not both.

[name="file-list"] {
    display: none !important;
    height: 0px !important;
}

[name="file-list"] div[part="file-list"] {
    display: none !important;
}

[name="file-list"] {
    display: block !important;
    height: 1.5rem !important;
}

[name="file-list"] div[part="file-list"] {
    display: block !important;
}

p/s: This is my first experience using Vaadin in a project and I probably never going to use it again. Customizing anything in Vaadin is so time-consuming and painful.

Joshua Ting
  • 103
  • 7

1 Answers1

5

Styling in the shadow DOM can indeed be tricky. The simplified theming in Vaadin 19 helps a bit.

Where the @CssImport annotation is placed affects if the CSS should be included in the document, but not which components it affects. With themeFor, it will always be applied to all matching components.

What you can do is to use the :host selector to limit which upload components it applies to. Here I am using a class-based approach:

:host(.no-file-list) [name="file-list"] {
    display: none !important;
    height: 0px !important;
}

:host(.no-file-list) [name="file-list"] div[part="file-list"] {
    display: none !important;
}

I can then hide the file list in an upload component by adding a class:

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

    public FileUploadTest() {
        Upload uploadWithFileList = new Upload();
        Upload uploadWithoutFileList = new Upload();
        uploadWithoutFileList.addClassName("no-file-list");

        add(uploadWithFileList, uploadWithoutFileList);
    }
}
Erik Lumme
  • 5,202
  • 13
  • 27