Skip to content

Ext JS Theming and Styling — Custom Themes, CSS, and Visual Customization

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn about Ext JS Theming and Styling. We cover key concepts, practical examples, and best practices to help you master this topic.

Ext JS theming allows complete visual customization through CSS variables, component-level style overrides, custom themes built with Sencha Cmd, and responsive configuration for different screen sizes.

What You'll Learn

  • CSS variable system in Ext JS themes
  • Creating custom themes with Sencha Cmd
  • Component-level styling and overrides
  • Responsive Design with responsiveConfig
  • Performance considerations for custom themes

Why It Matters

Enterprise applications need consistent branding that matches company style guides. Ext JS themes control colors, fonts, spacing, and component appearance globally. Custom themes ensure a professional, branded experience without overriding individual component styles.

Real-World Use

A financial application using the company's brand colors (dark blue header, green accents, custom font stack), with a light dashboard theme and a dark trading theme that users can toggle, all built on a custom Ext JS theme package.

Theming Architecture

flowchart TD
    A[Custom Theme] --> B[Base Theme]
    B --> C[CSS Variables]
    A --> D[Component Styles]
    A --> E[Ext SASS/SCSS]
    A --> F[Images/Icons]
    D --> G[Panel]
    D --> H[Grid]
    D --> I[Button]
    D --> J[Form Field]
    C --> K[Colors]
    C --> L[Fonts]
    C --> M[Spacing]
    style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px

CSS Variable Overrides

// Override CSS variables globally (Ext JS 7+)
Ext.define('MyApp.overrides.Theme', {
  override: 'Ext.Component',
  // Applied to all components
  setStyle: function() {
    // Set CSS custom properties on the document root
    Ext.getDoc().setStyle('--base-color', '#1a237e');
    Ext.getDoc().setStyle('--base-highlight-color', '#283593');
    Ext.getDoc().setStyle('--base-light-color', '#e8eaf6');
    Ext.getDoc().setStyle('--base-alt-color', '#f5f5f5');
    Ext.getDoc().setStyle('--color', '#212121');
    Ext.getDoc().setStyle('--font-size', '14px');
    Ext.getDoc().setStyle('--font-family', "'Segoe UI', Roboto, sans-serif");
    Ext.getDoc().setStyle('--border-radius', '4px');
    this.callParent();
  }
});

Expected output: Setting CSS variables on the document root changes the appearance of all Ext JS components that reference these variables. Base color, font, and border radius are updated globally.

Custom Theme Package

# Create a custom theme with Sencha Cmd
sencha generate theme MyApp-theme /path/to/ext

# The generated structure:
# packages/
#   local/
#     MyApp-theme/
#       package.json
#       sass/
#         var/
#           component/
#         src/
#           component/
#       resources/
// sass/var/all.scss - Global variable overrides
$base-color: #1a237e;
$base-highlight-color: #283593;
$base-light-color: #e8eaf6;
$base-alt-color: #f5f5f5;
$color: #212121;
$font-family: 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
$font-size: 14px;
$border-radius: 4px;

// Panel variables
$panel-header-background-color: $base-color;
$panel-header-color: #ffffff;
$panel-header-font-size: 16px;
$panel-border-color: #c5cae9;

// Grid variables
$grid-header-background-color: $base-light-color;
$grid-header-color: $base-color;
$grid-row-cell-font-size: 13px;
$grid-row-cell-alt-background-color: #fafafa;
$grid-row-cell-selected-background-color: #c5cae9;

// Button variables
$button-default-background-color: $base-color;
$button-default-color: #ffffff;
$button-default-border-color: darken($base-color, 5%);
$button-toolbar-background-color: #ffffff;
$button-toolbar-color: $base-color;

// Form field variables
$form-field-border-color: #c5cae9;
$form-field-focus-border-color: $base-color;
$form-field-label-color: $color;

Expected output: The custom theme changes all panels to dark blue headers, light blue grid headers, styled buttons, and form fields with blue focus borders. The theme is compiled with Sencha Cmd and applied to the application.

Component-Level Styling

// 1. Inline style config
Ext.create('Ext.panel.Panel', {
  title: 'Styled Panel',
  style: {
    backgroundColor: '#e8f5e9',
    borderColor: '#66bb6a',
    borderWidth: '2px'
  },
  bodyStyle: {
    padding: '20px',
    fontSize: '16px'
  }
});

// 2. CSS class
Ext.create('Ext.button.Button', {
  text: 'Custom Button',
  cls: 'my-custom-button',
  // Add multiple classes
  cls: ['my-btn', 'my-btn-primary']
});

// 3. Component UI
Ext.create('Ext.panel.Panel', {
  title: 'Custom UI Panel',
  ui: 'custom-panel'
});

// Define the UI style
// sass/src/panel/Panel.scss
// @include extjs-panel-ui(
//   $ui: 'custom-panel',
//   $header-background-color: #ff9800,
//   $header-color: #ffffff,
//   $border-color: #e65100
// );

Expected output: Panels, buttons, and other components accept style, cls, and ui configurations for targeted visual customization.

Responsive Design

Ext.create('Ext.panel.Panel', {
  title: 'Responsive Panel',
  responsiveConfig: {
    // Desktop (> 800px)
    'width > 800': {
      width: 700,
      height: 400,
      layout: 'hbox'
    },
    // Tablet (481-800px)
    'width > 480 && width <= 800': {
      width: '100%',
      height: 350,
      layout: 'vbox'
    },
    // Mobile (<= 480px)
    'width <= 480': {
      width: '100%',
      height: 300,
      layout: 'vbox',
      collapsible: true,
      collapsed: true
    }
  }
});

// Responsive grid columns
Ext.create('Ext.grid.Panel', {
  responsiveConfig: {
    'width > 800': {
      columns: [
        { text: 'ID', width: 50 },
        { text: 'Name', flex: 2 },
        { text: 'Email', flex: 3 },
        { text: 'Phone', width: 130 },
        { text: 'Status', width: 100 },
        { text: 'Actions', width: 150 }
      ]
    },
    'width <= 800': {
      columns: [
        { text: 'Name', flex: 1 },
        { text: 'Email', flex: 2 },
        { text: 'Status', width: 80 }
      ]
    }
  }
});

Expected output: Panels and grids adjust their layout, size, columns, and visibility based on viewport width. ResponsiveConfig evaluates expressions and applies matching configs.

Dark Theme Toggle

Ext.define('MyApp.controller.Theme', {
  extend: 'Ext.app.Controller',
  init: function() {
    this.control({
      'button[action=toggleTheme]': {
        click: 'onToggleTheme'
      }
    });
  },
  onToggleTheme: function(btn) {
    var isDark = Ext.getDoc().hasCls('dark-theme');
    if (isDark) {
      this.applyLightTheme();
    } else {
      this.applyDarkTheme();
    }
  },
  applyDarkTheme: function() {
    Ext.getDoc().addCls('dark-theme');
    Ext.getDoc().removeCls('light-theme');
    // Update CSS variables for dark mode
    Ext.getDoc().setStyle('--background-color', '#121212');
    Ext.getDoc().setStyle('--text-color', '#e0e0e0');
    Ext.getDoc().setStyle('--surface-color', '#1e1e1e');
    Ext.getDoc().setStyle('--primary-color', '#90caf9');
    Ext.getDoc().setStyle('--border-color', '#333333');
    // Reapply application theme
    Ext.util.CSS.updateRule('.x-panel', 'background-color', '#1e1e1e');
    Ext.util.CSS.updateRule('.x-panel-header', 'background-color', '#333333');
    Ext.util.CSS.updateRule('.x-grid-row', 'background-color', '#1e1e1e');
    Ext.util.CSS.updateRule('.x-grid-row-alt', 'background-color', '#2a2a2a');
    // Save preference
    localStorage.setItem('theme', 'dark');
  },
  applyLightTheme: function() {
    Ext.getDoc().addCls('light-theme');
    Ext.getDoc().removeCls('dark-theme');
    Ext.getDoc().setStyle('--background-color', '#ffffff');
    Ext.getDoc().setStyle('--text-color', '#212121');
    Ext.getDoc().setStyle('--surface-color', '#f5f5f5');
    Ext.getDoc().setStyle('--primary-color', '#1a237e');
    Ext.getDoc().setStyle('--border-color', '#e0e0e0');
    localStorage.setItem('theme', 'light');
  }
});

Expected output: Clicking a toggle button switches between light and dark themes. CSS variables update immediately, and the preference is saved to localStorage for persistence.

Icon Customization

// Use Font Awesome icons instead of default PNGs
Ext.define('MyApp.overrides.Icon', {
  override: 'Ext.panel.Tool',
  // Use Font Awesome icons for panel tools
  getToolConfig: function() {
    var config = this.callParent();
    if (config.type === 'close') {
      config.iconCls = 'x-fa fa-times';
    } else if (config.type === 'maximize') {
      config.iconCls = 'x-fa fa-window-maximize';
    } else if (config.type === 'minimize') {
      config.iconCls = 'x-fa fa-window-minimize';
    } else if (config.type === 'gear') {
      config.iconCls = 'x-fa fa-cog';
    }
    return config;
  }
});

// Global icon configuration
Ext.setIconCls({
  // Default icons for common components
  close: 'x-fa fa-times',
  menu: 'x-fa fa-bars',
  refresh: 'x-fa fa-refresh',
  search: 'x-fa fa-search',
  add: 'x-fa fa-plus',
  delete: 'x-fa fa-trash',
  edit: 'x-fa fa-pencil',
  save: 'x-fa fa-floppy-o',
  cancel: 'x-fa fa-ban',
  // Custom application icons
  dashboard: 'x-fa fa-tachometer',
  users: 'x-fa fa-users',
  products: 'x-fa fa-cubes',
  reports: 'x-fa fa-bar-chart'
});

Expected output: All component icons are replaced with Font Awesome equivalents, giving a modern, consistent icon set across the entire application.

Performance and Theme Optimization

// 1. Disable unused component styles
Ext.require([
  'Ext.grid.Panel',
  'Ext.form.Panel',
  'Ext.tree.Panel',
  'Ext.chart.CartesianChart'
  // Don't require components you don't use
]);

// 2. Lazy load theme resources
Ext.Loader.loadScript('/resources/MyApp-theme-all.js', function() {
  // Theme loaded, now create the app
  Ext.application({ /* ... */ });
});

// 3. Use compact themes for non-critical components
// Sencha Cmd: sencha app build --theme MyApp-compact-theme

// 4. Disable animations on low-end devices
if (Ext.os.is.Android && Ext.os.version.lt('5')) {
  Ext.enableAnimations = false;
}

// 5. Sprite icons and images
// Use CSS sprites for custom icons to reduce HTTP requests
// Configure in sass/var/all.scss
$include-missing-icons: false; // Don't load individual PNG files

Expected output: Reduced CSS/JS payload by only including styles for used components. Animations disabled on older devices improves perceived performance.

Common Mistakes

  1. Overriding component styles globally with CSS - Direct CSS overrides on .x- classes break when Ext JS updates. Use the theme variable system or component UI instead.

  2. Not rebuilding after theme changes - SCSS variable changes require a Sencha Cmd build. Running the app without rebuilding shows old styles.

  3. Mixing too many fonts - Ext JS loads font files for icons. Adding custom web fonts increases page weight. Limit to one icon font and one UI font family.

  4. Forgetting responsive breakpoints - Themes tested only on desktop break on mobile. Set responsiveConfig on all major components and test at 320px, 768px, and 1280px.

  5. Using inline styles instead of theme variables - Inline styles override theme variables but create maintenance nightmares. A single variable change in the theme updates hundreds of components.

Practice Questions

  1. How do CSS variables control component appearance in Ext JS?
  2. What is the purpose of the ui config on a component?
  3. How would you create a theme that changes all button colors?
  4. What is responsiveConfig and how does it work?
  5. How do you implement a dark mode toggle?

Challenge: Build a fully themed application with: a custom theme package using brand colors, a dark mode toggle with localStorage persistence, responsive grid columns that hide columns on mobile, Font Awesome icon integration, custom component UI for primary and secondary buttons, and a settings panel where users can customize accent color and font size.

FAQ

What tools can I use to create Ext JS themes?

Sencha Cmd with the generate theme command creates a custom theme package. Sencha Themer provides a visual theme editor for drag-and-drop styling without writing SCSS.

Can I use Tailwind CSS or Bootstrap with Ext JS?

Yes, but scoped to non-Ext JS content. Ext JS components use their own CSS classes. Apply Tailwind/Bootstrap to custom HTML inside Ext JS containers using cls or html config.

How do I change the font of all components?

Override $font-family in your theme's SCSS variables file. This changes all component fonts globally. For individual components, use the component's font-family CSS variable.

What is the difference between cls and style in component config?

cls adds a CSS class (defined in your stylesheet). style applies inline CSS directly to the component's element. Use cls for reusable styles, style for one-off overrides.

How do I ensure my theme is accessible (WCAG)?

Use high-contrast color combinations, set proper font sizes, respect prefers-reduced-motion, and test with screen readers. Ext JS supports ARIA attributes that work with any theme.

Mini Project

Build a theming demo application with: a light and dark theme toggle with smooth transition, a theme settings panel (accent color picker, font size slider, border radius selector), responsive layout that switches from desktop sidebar to mobile bottom navigation, custom component UIs for panels, buttons, and form fields, Font Awesome icons for all toolbar actions, and theme preference saved to localStorage.

What's Next

Theming makes your app look professional. Learn how Ext JS Extensions and Plugins extend functionality with custom components, plugins, mixins, and reusable extensions.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro