How to Create a Dark Ext JS Theme (part 2)

Posted on in CSS Sass

I’ve been showing you how to develop a fancy dark theme, which kind of looks like Spotify. In Part 1 of the article, you learned about Fashion, Sencha Inspector, Themes, and variables. In Part 2, I’ll focus on more advanced concepts including: making unique components with Ext JS UIs, CSS overrides, and how to incorporate custom fonts or icons.

You can use this tutorial to help you build your theme for the Sencha Application Theming Contest.
The first prize winner gets $2,500!

Sign up now

Custom CSS Rules and Mixins

There are a few more things I did in my Spotifext theme to make it look awesome. I wrote some CSS rules to animate the button hovers, used custom fonts, and created my own button and tab panel variants to give it a unique look.

With the variables I described earlier, you can change the overall look and feel of the application and all its components. But sometimes, you just want to make certain components unique. See the image below of my working Spotifinder app. You can see that the tab panel doesn’t look like the default Ext JS tabs. The buttons can be square or round, in the colors green or gray. I’m using Ext JS UIs, which are Sass mixins under the hood. A mixin is a block of CSS rules that can be re-used throughout an app.

Here’s an example Sass mixin:

@mixin my-border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
}

The above Sass mixin can be used to create rounded corners. I need to write experimental browser prefixes, so I can support this CSS3 feature across all browsers. Instead of writing every CSS rule myself, I can just include the my-border-radius mixin and pass in an argument, so all the CSS rules will be available after compilation:

.box { @include border-radius(10px); }

In the compiled CSS, it will look like this (but minified):

.box {
-webkit-border-radius: 10px;
     -moz-border-radius: 10px;
      -ms-border-radius: 10px;
          border-radius: 10px;
}

Sass mixins are a great concept that can be used in Ext JS as well. We call them UIs, and they’re basically skins. Ext JS includes out-of-the-box UIs. For example, in the modern toolkit, we have UIs for back buttons, round buttons, and more, and it provides UIs you can reuse with your own parameters.

You can find these mixins in the Sencha API Docs. For example, look at Ext.button.Button, you’ll see Sass Mixins in all different states for buttons. To implement these mixins, you’ll use @include, then the mixin name in Ext JS, and then pass in the arguments.

Ext.button.Button

To create the nice rounded buttons, take a look here.

I used the below mixin code to create a new “scale: small” button. For arguments, I passed in the UI name: “round”, which I used in my view as ui: ‘round’), a font-weight, padding and a background color:

@include extjs-button-small-ui(
    $ui: 'round',
    $font-weight: bold,
    $padding: 5px,
    $background-color: $highlight-color 
);

You might have noticed that the buttons are animated, and the tab panel that looks like Spotify is a lot different from the provided Ext JS mixins. Take a look at my sass/src folder. In this directory, I’ve written all Ext JS mixins and custom Sass rules.

Buttons

Unique Buttons

As you can see in my application, my buttons are more custom than the configuration provided by the API. My app contains code to make smooth animations. On every rollover, the button slowly lights ups. I did this by using custom Sass / CSS code.

Take a look:

.x-btn-round-large,
.x-btn-round-medium,
.x-btn-round-small {
    &:hover {
      background-color: $highlight-color2;
      -webkit-transition: background-color 2s ease-out;
      -moz-transition: background-color 2s ease-out;
      -o-transition: background-color 2s ease-out;
      transition: background-color 2s ease-out;
    }
}

The CSS class names come from the mixin. I gave my small button the ui name: “round”. After I wire up this UI to my view code, I see in my browser DOM that the UI gave the component this class name: .x-btn-‹ui-name›-small.

All Sencha components get CSS class names by default with the .x- prefix. After that, it names the component (btn), then the UI name. For a button, it will also include the scale – or, if it’s in a toolbar. See mixin extjs-button-toolbar-small-ui.

The custom code I provided listens to the button hover. When I roll my mouse over the button, it will transition the background-color from the default background color (in my case black) to a new color (the green that I set in the background-color rule).

Unique Tabs

Sometimes you don’t want to use custom CSS code to add more functionality but instead to override the default look and feel. For example, when the UI mixin doesn’t provide the configuration you are looking for.

I did this to create unique-looking tabs. See the screenshot:

The code I used can be found here. Take a look at the .x-tab-bar-alternative CSS class.

You may be wondering when to use UI mixins versus mixins. UI mixins are great because they style the full application and contain code that supports every browser supported by Ext JS. The disadvantage is that your stylesheet code will grow. This is why I typically use UI mixins for styling, and rules that are re-used throughout my application.

CSS rules and overrides are great because they can be a quick solution. The disadvantage is that it’s complicated because you’ll need to test across browsers, and you really need to understand the generated DOM. I use CSS overrides and rules in case the UI mixin doesn’t provide the configuration, or when I need the CSS rule in only a few places.

Incorporating Fonts

The last thing I did in my custom theme was incorporate custom fonts and icons (which are icon fonts). Please take a look at this file.

I included two custom fonts. One google font (from the Google font provider), and one icon font called Spotifinder that I created on this website. I selected my own icon set, and I generated a font out of it.

Both fonts are @font-face fonts, so you have to include the different font extensions for various browsers in your stylesheet. For the icon font, I had to put them in manually. See the four font extensions. Usually when you create a custom icon font on an icon website like icomoon, you’ll be able to download the stylesheet that goes with it. In my case, I could just copy & paste it, but in some cases you’ll have to write it yourself.

The google font was really easy because Sencha provides a global UI mixin. This mixin puts the code for all the extensions in your compiled CSS code by importing the code from Google. See the docs. Please note that using custom fonts from a font provider (like Google Font) requires an additional request to the font. An alternative way to do it is to download an @font-face font yourself (from a website such as http://www.fontsquirrel.com/) and provide the full import code yourself. Just like I did for the icon font.

Once your font is correctly imported, you can start using it. I’m using the Google font by pointing the $font-family variable to it here.

Conclusion
That’s it! Now, I’ve explained everything you need to know to create an awesome theme, such as the Spotifext theme. Check out the screenshot below to see how it might look in a real-life application.

Don’t forget to sign up for the Sencha Application Theming Contest. The first prize winner gets $2,500!

Spotifext theme

Resources:

Ext JS Theming Guide
My SenchaCon Presentation
Tutorial Demo Files

Creating Theme-Specific Overrides in Ext JS

Posted on in CSS Ext JS Sass Sencha

Ext JS provides a number of functions that make it simple to create and work with classes. It also provides a series of functions to extend or override existing JavaScript classes. This means you can add behaviors and create your own classes, or override the behavior of some functions. In this article, we will show you how to use theme-specific class overrides.

You probably already know how to create an Ext JS class override. For example, you might want to change default behavior or patch the framework. In that case, you would create the class override using this code:

Ext.define('SomeClassName', {
    override : 'Ext.panel.Panel'
 
    //the override: by default, all panels will have a 200px width
    width : 200 
});

The first questions that come up are: what do you name this override class and where do you put it. You may be creating a class override that is specific to a theme. Wouldn’t it be nice, to have this JavaScript override bundled together with your custom theme? For example, in your custom theme, all panels should have a box-shadow. Or perhaps, you created an awesome CSS3 animation that will be visible any time you open a popup window. Unfortunately, the old versions of Internet Explorer can’t handle CSS3, so you might want to write a JavaScript fallback. In both cases, the default functionality change is visual. So, where in your file structure can you create these overrides, so they don’t break any other themes?

The trick is the overrides folder. With Sencha Cmd 3.1, it’s possible for applications and packages to save class overrides in the overrides folder. By default, when you generate a (theme) package, it already contains such a folder, and it has been set up to support overrides.

Let’s create a JavaScript fallback. For a simple animation, we will animate the opacity when opening a popup window.

Create the following file structure in your theme package, (let’s assume the name of this package is called: MyTheme ):

packages
> MyTheme
> > overrides
> > > window
> > > > Window.js

This file structure maps to the file structure of the framework for Ext.window.Window.

Let’s define the class:

Ext.define('MyTheme.window.Window', {
 
});

This class will override from Ext.window.Window:

Ext.define('MyTheme.window.Window', {
    override : 'Ext.window.Window'
 
});

Let’s test if this override works. First, run this from the command-line:

sencha app refresh

At this point, the previous code won’t change any functionality yet. Let’s output a console log as soon as the class is created, and test it in a browser:

Ext.define('MyTheme.window.Window', {
    override : 'Ext.window.Window'
 
}, function(){
    console.log("Oh yes, my override works!");
});

Let’s create the custom behavior. This override will add an animation on the beforeshow listener of a window:

listeners: {
    beforeshow: function(mywindow){
 
    }
}

The beforeshow listener will create a new animation (Ext.fx.Anim), so first you have to require the animation in your class:

requires: ['Ext.fx.Anim'],

Next, you include the code for creating the animation in the beforeshow event. For now, we will create a very simple animation, which changes the opacity to smoothly display the window (mywindow) from hidden to 100% visibility:

Ext.create('Ext.fx.Anim', {
    target: mywindow, //argument of the beforeshow event
    duration: 1000, //ms
    from: {
        opacity: 0
    },
    to: {
        opacity: 1
    }
});

Now, you can test if the animation works.

To top it off, let’s create a nice CSS3 animation for the modern browsers as well. We will wrap the Ext JS animation into a check that will only execute when the browser is an old version of Internet Explorer (IE9 or lower):

if(Ext.isIE9m) {
 
}

Confirm your code looks like this:

Ext.define('MyTheme.window.Window', {
    override : 'Ext.window.Window',
 
    requires: ['Ext.fx.Anim'],
    closeAction: 'hide',
    listeners: {
        beforeshow: function(mywindow){
 
            if(Ext.isIE9m) {
                Ext.create('Ext.fx.Anim', {
                    target: mywindow,
                    duration: 1000,
                    from: {
                        opacity: 0
                    },
                    to: {
                        opacity: 1
                    }
                }); 
            }
        }
    }
});

The only thing that is missing is the Sass code for the CSS3 animation. We will use Compass for that.

In the theme package, we can add the following Sass code to packages/MyTheme/sass/src/window/Window.scss. The code below shows the same animation that we coded in the JavaScript file:

@import "compass/css3/transition";
 
.x-window.x-hide-offsets {
    @include opacity(0);
}
 
.x-window {
    @include single-transition(opacity, 1000ms);
    @include opacity(1);
}

You will need to compile the Sass stylesheet to production-ready CSS code. Since this is included in Sencha Cmd and the Sencha build process, the Sass stylesheet will be automatically compiled when building the application with Sencha Cmd.

For now, we don’t need to build the whole application, we just want to quickly test the animation and only compile the stylesheet. You can achieve this by running one of the following commands from the command-line:

sencha ant sass

or

sencha app watch

The first command runs the Apache Ant task to compile the Sass once. The second command is more powerful, but it requires you to download and install Java Development Kit 7. You can compare sencha app watch with the Compass command: compass watch. Sencha Cmd watches the app and every time you hit save, Sencha Cmd builds your app and compiles your Sass Stylesheets. When changes are detected, only the minimum amount of work necessary is performed to bring your app and its CSS up to date, saving you from rebuilding your Sass.

Voila — the animation works in old and new browsers.

If you’d like to learn more about this and many other advanced Ext JS theming techniques, take our Advanced Theming Ext JS course. Check out http://www.sencha.com/training/ to join one of the Theme331 Advanced Theming classes located around the world or join an online class.