Configuring and Loading Theme Style Sheets in vSphere Client Remote Plug-Ins

After you compile the output style sheets for your plug-in user interface, you write front-end code to load the style sheets that cause your plug-in to conform to the style selected in the vSphere Client.

Prerequisites

  • Refactor the input style sheets for the plug-in so that they isolate theme-dependent colors and styles in separate style sheets as CSS variables.
  • Configure theme-dependent icons in the plug-in manifest file.
  • Build output style sheets into a base style sheet and a style sheet for each theme.

Procedure

  1. Load and configure polyfill libraries to provide CSS variable support in Internet Explorer 11.
    If you use css-vars-ponyfill, consider whether to configure options to create a MutationObserver and whether to remove CSS rulesets and declarations that do not reference a CSS custom property value. For more information about configuring css-vars-ponyfill, see https://github.com/jhildenbiddle/css-vars-ponyfill/tree/v1.17.1#optionswatch and https://github.com/jhildenbiddle/css-vars-ponyfill/tree/v1.17.1#optionsonlyvars.
    The vSphere Client SDK includes a remote plug-in sample that uses css-vars-ponyfill. The following example is borrowed from the file html-client-sdk/samples/remote-plugin-sample/src/main/ui/src/index.html.
    <script type="text/javascript" src="scripts/css-vars-ponyfill.js"></script>                                    
    // Initialize CSS vars to configure polyfill.
    cssVars({
              watch: true,
              onlyVars: true
    });
    The following example is borrowed from the file html-client-sdk/samples/remote-plugin-sample/src/main/ui/.angular-cli.json.
      "assets": [                                    
        "assets",
        {
          "glob":
          "css-vars-ponyfill.js",
          "input": "../node_modules/css-vars-ponyfill/dist/",
          "output": "scripts/
        },
       … 
      ]
  2. Load the base style sheet initially.
    The following example is borrowed from html-client-sdk/samples/remote-plugin-sample//src/main/ui/src/index.html.
    <link rel="stylesheet" type="text/css" href="styles.bundle.css">
  3. Load and initialize the vSphere Client JavaScript API.
    <script type="text/javascript" src="/api/ui/htmlClientSdk.js"></script>
    <script type="text/javascript">
      htmlClientSdk.initialize(init_plugin_view());
    </script>
    For examples in the SDK, see html-client-sdk/samples/remote-plugin-sample//src/main/ui/src/index.html and html-client-sdk/samples/remote-plugin-sample//src/main/ui/src/app/app.component.ts.
  4. Load the style sheet for the current theme initially and whenever the style changes.
    The following example is adapted from html-client-sdk/samples/remote-plugin-sample/src/main/ui/src/app/app.component.ts.
    if (this.globalService.htmlClientSdk.app.getTheme &&
      this.globalService.htmlClientSdk.event.onThemeChanged) {
        this.loadTheme(true, this.globalService.htmlClientSdk.app.getTheme());
        this.globalService.htmlClientSdk.event.onThemeChanged(
                             this.loadTheme.bind(this, false));
      } else {
        this.loadTheme(true, { name: 'light' });
      }
    
    private loadTheme(firstLoad: boolean, theme: any): void {
      let themeName: string = theme.name;
      let supportedThemeNames: string[] = ['light', 'dark'];
      if (supportedThemeNames.indexOf(themeName) === -1) {
        themeName = supportedThemeNames[0];
      }
      let styleSheetLinkElement =
        (<HTMLLinkElement> document.getElementById('theme-stylesheet-link'));
      let themeCssUrl = `theme-${themeName}.bundle.css`;
    
      if (firstLoad) {
        let initialThemeLoadCompleteListener = (event: Event) => {
          this.initialThemeLoadComplete = true;
          styleSheetLinkElement.removeEventListener('load', 
                         initialThemeLoadCompleteListener);
          styleSheetLinkElement.removeEventListener('error',
                          initialThemeLoadCompleteListener);
        };
    
        styleSheetLinkElement.addEventListener('load',
                    initialThemeLoadCompleteListener);
        styleSheetLinkElement.addEventListener('error',
                     initialThemeLoadCompleteListener);
      }
    
      styleSheetLinkElement.setAttribute("href", themeCssUrl);
      document.documentElement.setAttribute("data-theme", themeName);
    }