Using Icons from Other Font Libraries

To enhance the custom theme, you may need to create icons and embed them into fonts, as well as use any external icons library. As an example, consider using the Font Awesome 5 with the Brands style.

  1. Create the enum class implementing the com.vaadin.server.FontIcon interface for the new icons:

    public enum FontAwesome5Brands implements FontIcon {
    
        JAVA(0XF4E4);
    
        public static final String FONT_FAMILY = "FontAwesome5Brands";
        private final int codepoint;
    
        FontAwesome5Brands(int codepoint) {
            this.codepoint = codepoint;
        }
    
    
        @Override
        public String getFontFamily() {
            return FONT_FAMILY;
        }
    
        @Override
        public int getCodepoint() {
            return codepoint;
        }
    
        @Override
        public String getHtml() {
            return GenericFontIcon.getHtml(FONT_FAMILY, codepoint);
        }
    
        @Override
        public String getMIMEType() {
            throw new UnsupportedOperationException(FontIcon.class.getSimpleName()
                    + " should not be used where a MIME type is needed.");
        }
    
        public static FontAwesome5Brands fromCodepoint(final int codepoint) {
            for (FontAwesome5Brands f : values()) {
                if (f.getCodepoint() == codepoint) {
                    return f;
                }
            }
            throw new IllegalArgumentException(
                    "Codepoint " + codepoint + " not found in FontAwesome 5");
        }
    }
  2. Add new styles to the custom theme. We recommend creating special subfolder fonts in the main folder of the custom theme, for example, themes/helium-extended/fonts. Put the styles and font files in their own subfolders, for example, fonts/fontawesome.

    Files of fonts are represented by the following extensions:

    • .eot,

    • .svg,

    • .ttf,

    • .woff,

    • .woff2.

    The set of fonts fontawesome with the Brands style consists of 5 joint used files: fa-brands-400.eot, fa-brands-400.svg, fa-brands-400.ttf, fa-brands-400.woff, fa-brands-400.woff2.

    If you want to use other styles (Solid, Regular, and so on), you need to define a unique class name for every FontAwesome variant. Also, you need to implement separate IconSets and Providers for every variant.

  3. Create a file with styles that includes @font-face and a CSS class with the icon style. Below is an example of the fontawesome5.scss file, where the FontAwesome5Brands class name corresponds to the value returned by the FontIcon.getFontFamily() method:

    @mixin font-icon-style {
      speak: none;
      font-style: normal;
      font-weight: normal;
      font-variant: normal;
      text-transform: none;
      line-height: 1;
    
      /* Better Font Rendering =========== */
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }
    
    /* FontAwesome 5 Brands */
    
    @mixin font-awesome-5-brands-style {
      font-family: 'FontAwesome5Brands';
      @include font-icon-style;
    }
    
    @font-face {
      font-family: 'FontAwesome5Brands';
      src: url('fa-brands-400.eot?hwgbks');
      src: url('fa-brands-400.eot?hwgbks#iefix') format('embedded-opentype'),
      url('fa-brands-400.ttf?hwgbks') format('truetype'),
      url('fa-brands-400.woff?hwgbks') format('woff'),
      url('fa-brands-400.svg?hwgbks#icomoon') format('svg');
      font-weight: normal;
      font-style: normal;
    }
    
    .FontAwesome5Brands {
      @include font-awesome-5-brands-style;
    }
  4. Create a reference to the file with font styles in helium-extended.scss or other files of the custom theme:

    @import "fonts/fontawesome5/fontawesome5";
  5. Then create a new icon set which is an enumeration implementing the Icons.Icon interface:

    public enum FontAwesome5Icon implements Icons.Icon {
    
        JAVA("font-awesome5-brands-icon:JAVA");
    
        protected String source;
    
        FontAwesome5Icon(String source) {
            this.source = source;
        }
    
        @Override
        public String source() {
            return source;
        }
    
        @Override
        public String iconName() {
            return name();
        }
    }
  6. Create a new IconProvider.

    For managing custom icon sets Jmix framework provides the mechanism that consists of IconProvider and IconResolver.

    IconProvider is a marker interface that can provide resources (com.vaadin.server.Resource) by the icon path.

    The IconResolver bean obtains all beans that implement the IconProvider interface and iterates over them to find the one that can provide a resource for the icon.

    To use this mechanism, you should create your implementation of IconProvider:

    @Order(10)
    @Component("sample_FontAwesome5BrandsIconProvider")
    public class FontAwesome5BrandsIconProvider implements IconProvider {
    
        public static final String FONT_AWESOME_5_BRANDS_PREFIX = "font-awesome5-brands-icon:";
        private final Logger log = LoggerFactory.getLogger(FontAwesome5BrandsIconProvider.class);
    
        @Override
        public Resource getIconResource(String iconPath) {
            Resource resource = null;
    
            iconPath = iconPath.split(":")[1];
    
            try {
                resource = ((Resource) FontAwesome5Brands.class
                        .getDeclaredField(iconPath)
                        .get(null));
            } catch (IllegalAccessException | NoSuchFieldException e) {
                log.warn("There is no icon with name {} in the FontAwesome5Brands icon set", iconPath);
            }
    
            return resource;
        }
    
        @Override
        public boolean canProvide(String iconPath) {
            return !Strings.isNullOrEmpty(iconPath)
                    && iconPath.startsWith(FONT_AWESOME_5_BRANDS_PREFIX);
        }
    }

    Here we explicitly assign an order for this bean with the @Order annotation.

  7. Register your icon set in the application.properties file:

    jmix.ui.icons-config = ui.ex1.icon.FontAwesome5Icon

Now you can use new icons by direct reference to their class and enum element in the XML descriptor of the screen:

<button icon="font-awesome5-brands-icon:JAVA"/>

or in the Java controller:

cIconBtn.setIconFromSet(FontAwesome5Icon.JAVA);

Overriding Icons with Icon Sets

The mechanism of icon sets enables you to override icons from other sets. To do this, you should create and register a new icon set (enumeration) with the same icons (options) but with different icon paths (source). In the following example, the new MyIcon enum is created to override the standard icons from the JmixIcon set.

  1. Create the new icon set:

    public enum NewIcon implements Icons.Icon {
    
        OK("classpath:/icon/custom-ok.png");
    }
  2. Register the new icon set in application.properties:

    jmix.ui.icons-config = ui.ex1.icon.NewIcon

Now, the new OK icon will be used instead of the standard one:

@Autowired
private Icons icons;

@Subscribe
protected void onInit(InitEvent event) {
    okIconBtn.setIcon(icons.get(JmixIcon.OK));
}

In case you need to ignore redefinitions, you still can use the standard icons by using the icon source instead of the option name:

<button caption="Custom" icon="font-icon:CHECK"/>

or

oIconBtn.setIcon(JmixIcon.OK.source());