Sencha recently introduced a Sass and Compass based theming system to customise the look and feel of Ext JS 4.x web applications. I recently had a play around to see how easy it would be to customise a button in Ext JS 4.1.

I’m using:

  • Mac OS X 10.7.4 (Lion)
  • Ext JS 4.1
  • Compass 0.12.1
  • Sass 3.1.17
  • SenchaSDKTools-1.2.3

To keep things simple, I’m going to modify one of the Ext JS 4.1 examples so you don’t have to create a new project to see how it works.

  1. First up, download Ext JS 4.1 (GPL).
  2. Unzip the download to your local web server. Note. If you are on a Mac you already have Apache web server installed. Make sure your firewall is on Apple -> System Preferences… -> Security and Privacy -> Firewall tab. Next, go to Apple -> System Preferences… -> Sharing. Check “Web Sharing” and select  ”Open Computer Website Folder”. Drop the exploded download “extjs-4.1.0″ into this folder (/Library/WebServer).
  3. Check that your web server is working by opening a browser and navigating to “http://localhost/extjs-4.1.0/examples/form/checkout.html”. You should see something like this:
  4. Before we go any further we need to install Compass. If you are on a Mac you already have Xcode which automatically installs Ruby so you are ready to install the Compass gem on the command line. Open a Terminal and enter:
  5. $ sudo gem install compass
  6. Download and install Sencha SDK Tools. This step is optional but recommended if you are developing your own apps and wish to utilise the slicer and/or JSBuilder tools at a later date.
  7. Back in the Terminal, navigate to “/Library/WebServer/Documents/extjs-4.1.0/examples/form”:
  8. $ cd /Library/WebServer/Documents/extjs-4.1.0/examples/form
  9. Copy the “resources” template over from the Ext JS distribution to the current directory:
  10. $ cp -rf /Library/WebServer/Documents/extjs-4.1.0/resources/themes/templates/* .
  11. Change to the “resources” directory:
  12. $ cd resources
  13. Make an “images” directory:
  14. $ mkdir images
    $ cd images
    $ mkdir default
  15. Copy the “default” image resources over from the Ext JS distribution to the “default” directory you just created.
  16. $ cp -rf /Library/WebServer/Documents/extjs-4.1.0/resources/themes/images/default/* default
  17. Edit “config.rb” as follows (if you don’t like Vim use your favourite text editor) to configure the path to Ext JS 4.1 SDK:
  18. $ cd /Library/WebServer/Documents/extjs-4.1.0/examples/form/resources/sass
    $ vim config.rb
    ...
    # $ext_path: This should be the path of the Ext JS SDK relative to this file
    $ext_path = "../../../../../extjs-4.1.0"
    ...
  19. It’s time to customise “my-ext-theme.scss” as follows to create a new button UI called “purple”. Replace the contents of this file with the following:
  20. $ vim my-ext-theme.scss
    // Unless you want to include all components, you must set $include-default to false
    // IF you set this to true, you can also remove lines 10 to 38 of this file
    $include-default: false;
    
    // Insert your custom variables here.
    //$base-color: #dabeff;
    
    $light-purple: #dabeff;
    $medium-purple: #9e7dcb;
    
    @import 'ext4/default/all';
    
    // You may remove any of the following modules that you
    // do not use in order to create a smaller css file.
    @include extjs-boundlist;
    @include extjs-button;
    @include extjs-btn-group;
    @include extjs-form;
        @include extjs-form-field;
        @include extjs-form-fieldset;
        @include extjs-form-checkboxfield;
        @include extjs-form-checkboxgroup;
        @include extjs-form-triggerfield;
    @include extjs-panel;
    @include extjs-qtip;
    @include extjs-window;
    @include extjs-messagebox;
    @include extjs-viewport;
    
    @include extjs-button-ui(
    'purple-small',
    
    $border-radius: $button-small-border-radius,
    $border-width: $button-small-border-width, 
    
    $border-color: saturate($light-purple,10),
    $border-color-over: darken($light-purple,10),
    $border-color-focus: $light-purple,
    $border-color-pressed: darken($light-purple, 25),
    $border-color-disabled: gray,
    
    $padding: $button-small-padding,
    $text-padding: $button-small-text-padding,
    
    $background-color: saturate($light-purple,10),
    $background-color-over: darken($light-purple,10),
    $background-color-focus: $light-purple,
    $background-color-pressed: darken($light-purple,25),
    $background-color-disabled: gray,
    
    $background-gradient: color-stops(darken($light-purple, 10) 20%,darken($medium-purple, 10) 80%,darken($medium-purple, 10)),
    $background-gradient-over: color-stops(darken($light-purple, 15) 20%,darken($medium-purple, 15) 80%,darken($medium-purple, 15)),
    $background-gradient-focus: color-stops(saturate($light-purple, 10) 20%,saturate($medium-purple, 10) 80%,saturate($medium-purple, 10)),
    $background-gradient-pressed: color-stops(darken($light-purple, 15) 20%,darken($medium-purple, 15) 80%,darken($medium-purple, 15)),
    $background-gradient-disabled: $button-default-background-gradient-disabled,
    
    $color: $button-default-color,
    $color-over: $button-default-color-over,
    $color-focus: $button-default-color-focus,
    $color-pressed: $button-default-color-pressed,
    $color-disabled: $button-default-color-disabled,
    
    $font-size: $button-small-font-size,
    $font-size-over: $button-small-font-size-over,
    $font-size-focus: $button-small-font-size-focus,
    $font-size-pressed: $button-small-font-size-pressed,
    $font-size-disabled: $button-small-font-size-disabled,
    
    $font-weight: $button-small-font-weight,
    $font-weight-over: $button-small-font-weight-over,
    $font-weight-focus: $button-small-font-weight-focus,
    $font-weight-pressed: $button-small-font-weight-pressed,
    $font-weight-disabled: $button-small-font-weight-disabled,
    
    $font-family: $button-small-font-family,
    $font-family-over: $button-small-font-family-over,
    $font-family-focus: $button-small-font-family-focus,
    $font-family-pressed: $button-small-font-family-pressed,
    $font-family-disabled: $button-small-font-family-disabled,
    
    $icon-size: $button-small-icon-size
    );
    
    // This line changes the location of your images when creating UIs to be relative instead of within the ExtJS directory.
    // You MUST set this to true/string value if you are creating new UIs + supporting legacy browsers.
    // This only applies to new UIs. It does not apply to default component images (i.e. when changing $base-color)
    // The value can either be true, in which case the image path will be "../images/"
    // or a string, of where the path is
    $relative-image-path-for-uis: true; // defaults to "../images/" when true
  21. To turn our SCSS file into CSS, we need to compile it with Compass:
  22. $ compass compile my-ext-theme.scss
  23. The CSS file “my-ext-theme.css” is created under “/Library/WebServer/Documents/extjs-4.1.0/examples/form/resources/css”. Note. To avoid compiling every time we make a change, set up a watch on “my-ext-theme.scss” so that any future changes to this file are automatically compiled for us:
  24. $ compass watch my-ext-theme.scss
  25. Now we need to modify “checkout.html” to use our CSS file:
  26. $ vim ../../checkout.html
    ...
    <!-- ExtJS -->
    <link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
    <script type="text/javascript" src="../../ext-all.js"></script>
    <link rel="stylesheet" type="text/css" href="resources/css/my-ext-theme.css">
    ...
  27. To use our new button UI we need to modify “checkout.js” so that the “Complete Purchase” button specifies the “purple” button UI configuration:
  28. $ vim ../../checkout.js
    buttons: [{
                text: 'Reset',
                handler: function() {
                    this.up('form').getForm().reset();
                }
            }, {
                text: 'Complete Purchase',
                width: 150,
                ui: 'purple',
                handler: function() {
                    var form = this.up('form').getForm();
                    if (form.isValid()) {
                        Ext.MessageBox.alert('Submitted Values', form.getValues(true));
                    }
                }
            }]
  29. It’s time to preview our changes. Back in the browser, refresh “http://localhost/extjs-4.1.0/examples/form/checkout.html”. Note. If you are having issues seeing CSS changes in the browser, try clearing your cache (CTRL+Shift+delete) or inspecting the CSS for the page in a tool such as Firebug.
  30. Lets go one step further and change the base colour in “my-ext-theme.scss”. The “base-color” variable is a Ext JS global which we will set to the value of our custom “light-purple” variable:
  31. $ vim my-ext-theme.scss
    ...
    // Insert your custom variables here.
    $light-purple: #dabeff;
    $medium-purple: #9e7dcb;
    $base-color: $light-purple;
    ...
  32. Because we set up a watch earlier, all we need to do is save the file and refresh the page in the browser:

If you’re looking for the official docs to get started with Ext JS 4.x theming, checkout the Theming Learning Guide.