Ext JS Components — Configuration, Lifecycle, and Customization
In this tutorial, you will learn about Ext JS Components. We cover key concepts, practical examples, and best practices to help you master this topic.
Ext JS components are configurable objects with a defined lifecycle — init, render, destroy — that form the building blocks of every Ext JS application interface.
What You'll Learn
- Component configuration and xtype system
- Component lifecycle events (beforerender, render, afterrender, destroy)
- Finding components with ComponentQuery
- Creating custom components
- Managing component state
Why It Matters
Every UI element in Ext JS is a component. Understanding their lifecycle, configuration, and how to find them is essential for building any Ext JS application.
Real-World Use
A dashboard where each widget (grid, chart, form) is a component. Widgets are added and removed dynamically, and the lifecycle ensures proper initialization and cleanup.
Component Lifecycle
flowchart LR
A[Ext.create] --> B[beforeinit]
B --> C[initComponent]
C --> D[beforeRender]
D --> E[Render]
E --> F[afterRender]
F --> G[Active State]
G --> H[beforeDestroy]
H --> I[Destroy]
style C fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Creating and Configuring Components
// Using Ext.create
var panel = Ext.create('Ext.panel.Panel', {
title: 'My Panel',
width: 400,
height: 300,
collapsible: true,
html: 'Panel content',
renderTo: Ext.getBody()
});
// Using xtype (lazy instantiation)
Ext.create('Ext.container.Viewport', {
items: [{
xtype: 'panel',
title: 'Lazy Panel',
html: 'This panel is created when the viewport renders'
}]
});
// Updating configuration after creation
panel.setTitle('Updated Title');
panel.setWidth(500);
panel.collapse();
Expected output: The panel renders with a title, width, height, and collapsible feature. xtype defers creation until the container renders.
Component Lifecycle Events
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.panel.Panel',
title: 'Lifecycle Demo',
initComponent: function() {
console.log('1. initComponent');
this.html = 'Lifecycle in action';
this.callParent(); // Important: always call parent
},
listeners: {
beforerender: function() {
console.log('2. beforerender');
},
render: function() {
console.log('3. render');
},
afterrender: function() {
console.log('4. afterrender');
},
destroy: function() {
console.log('5. destroy');
}
}
});
Expected output: The console logs show the order: initComponent, beforerender, render, afterrender, then destroy when the component is removed.
ComponentQuery
Find components anywhere in the hierarchy:
// Find by xtype
var allPanels = Ext.ComponentQuery.query('panel');
var grids = Ext.ComponentQuery.query('grid');
// Find by ID or itemId
var myPanel = Ext.ComponentQuery.query('#userGrid')[0];
// Find by attribute
var disabledButtons = Ext.ComponentQuery.query('button[disabled=true]');
// Find by class
var customWidgets = Ext.ComponentQuery.query('myapp-customwidget');
// Relative queries (from a container)
var container = Ext.getCmp('mainContainer');
var children = container.query('panel');
var firstChild = container.down('grid');
var parent = firstChild.up('viewport');
Expected output: ComponentQuery returns arrays of matching components. down() returns the first child match. up() traverses upward to find a parent.
Creating Custom Components
Ext.define('MyApp.view.InfoCard', {
extend: 'Ext.panel.Panel',
xtype: 'infocard', // Custom xtype for lazy instantiation
config: {
iconCls: '',
description: '',
value: 0
},
initComponent: function() {
Ext.apply(this, {
cls: 'info-card',
layout: 'fit',
items: [{
xtype: 'container',
layout: 'vbox',
padding: 15,
items: [{
xtype: 'component',
cls: 'info-card-icon',
html: '<span class="' + this.iconCls + '"></span>'
}, {
xtype: 'component',
cls: 'info-card-value',
html: '<h2>' + this.value + '</h2>'
}, {
xtype: 'component',
cls: 'info-card-desc',
html: '<p>' + this.description + '</p>'
}]
}]
});
this.callParent();
},
updateValue: function(newValue) {
this.down('.info-card-value').update('<h2>' + newValue + '</h2>');
}
});
// Usage
Ext.create('MyApp.view.InfoCard', {
title: 'Revenue',
iconCls: 'fa-dollar',
description: 'Total revenue this quarter',
value: 125000,
renderTo: Ext.getBody()
});
Referencing Components
// By id (not recommended for reusable components)
var panel = Ext.getCmp('myPanelId');
// By itemId (recommended - scoped to parent)
var container = Ext.create('Ext.container.Container', {
items: [{
itemId: 'myButton',
xtype: 'button',
text: 'Click Me'
}]
});
var btn = container.getComponent('myButton');
// By reference (Ext JS 5+)
Ext.define('MyApp.view.Main', {
reference: 'mainView',
items: [{
xtype: 'button',
reference: 'saveButton', // Access via this.lookupReference('saveButton')
text: 'Save'
}]
});
Component State Management
Ext.define('MyApp.view.StatefulPanel', {
extend: 'Ext.panel.Panel',
stateful: true,
stateId: 'myStatefulPanel',
stateEvents: ['collapse', 'expand', 'resize'],
getState: function() {
return {
collapsed: this.collapsed,
width: this.getWidth(),
height: this.getHeight(),
x: this.getPosition()[0],
y: this.getPosition()[1]
};
},
applyState: function(state) {
if (state.collapsed) this.collapse();
this.setSize(state.width, state.height);
this.setPosition(state.x, state.y);
}
});
Common Mistakes
Forgetting callParent() in initComponent - Failing to call
this.callParent()breaks the component's initialization chain and causes unpredictable errors.Using Ext.getCmp() with reusable components - IDs must be unique. Use itemId with getComponent() or reference for reusable components.
Modifying config after creation via direct property access - Use setter methods:
setTitle(),setWidth(), notthis.title = 'New'.Not destroying components - Call
.destroy()when removing a component to trigger cleanup of event listeners and child components.Overriding the wrong lifecycle method - Override
initComponentfor one-time setup,afterRenderfor post-render operations, andbeforeDestroyfor cleanup.
Practice Questions
- What is the correct order of the component lifecycle events?
- How does xtype differ from Ext.create?
- What method is used to find components by xtype?
- Why should you call callParent() in initComponent?
- How do you access a child component by its itemId?
Challenge: Create a custom StatusBar component that extends Ext.toolbar.Toolbar. It should display the current time (updating every second), a connection status indicator, and the number of active users. Register it with a custom xtype.
FAQ
Mini Project
Build a custom MetricWidget component that displays a title, value, trend arrow (up/down/flat), and a sparkline chart. Use it in a dashboard with four instances showing different metrics.
What's Next
Components live inside containers. Learn how containers and layouts arrange and manage child components in different visual arrangements.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro