1. Architecture Overview
Element UI is a comprehensive Vue 2.x component library providing 67+ UI components, a theme system built on SCSS, an i18n framework supporting 50+ languages, and a set of internal utilities for DOM manipulation, popup management, and form validation. The library is published as element-ui on npm (v2.15.14) and distributed as both ES module and UMD bundles.
Architecture Diagram
element-ui (npm package)
├── src/index.js ← Auto-generated entry, registers all 67+ components
│ ├── Vue.use(ElementUI) ← Global install: components + directives + prototypes
│ └── Vue.prototype.$ELEMENT ← Global config (size, zIndex)
│
├── packages/ ← 67+ component packages
│ ├── {component}/index.js ← Package entry (imports src/main.vue, sets install())
│ └── {component}/src/ ← Component implementation (.vue + .js)
│
├── src/
│ ├── mixins/ ← Shared behaviors (emitter, focus, locale, migrating)
│ ├── directives/ ← Internal directives (mousewheel, repeat-click)
│ ├── locale/ ← i18n engine + 50+ lang packs
│ ├── transitions/ ← Collapse transition component
│ └── utils/ ← DOM, date, popup, popper, scrollbar, types, etc.
│
├── packages/theme-chalk/ ← SCSS theme (compiled via gulp to CSS)
│ └── src/ ← Per-component .scss files + shared variables
│
├── types/ ← TypeScript declarations
├── examples/ ← Demo site (webpack-dev-server)
├── test/ ← Unit tests (karma + mocha + chai + sinon)
└── build/ ← Webpack configs + build scripts
Component Inventory
Element UI ships 67 registerable components plus the CollapseTransition utility component. They are organized into these categories:
| Category | Components |
|---|---|
| Basic | Button, ButtonGroup, Icon, Link |
| Layout | Container, Header, Aside, Main, Footer, Row, Col, Divider |
| Form | Input, InputNumber, Radio, RadioGroup, RadioButton, Checkbox, CheckboxButton, CheckboxGroup, Select, Option, OptionGroup, Switch, Slider, DatePicker, TimePicker, TimeSelect, Upload, Rate, ColorPicker, Transfer, Form, FormItem, Cascader, CascaderPanel, Autocomplete |
| Data | Table, TableColumn, Tag, Tree, Pagination, Badge, Avatar, Skeleton, SkeletonItem, Empty, Descriptions, DescriptionsItem, Result, Statistic, Progress |
| Navigation | Menu, Submenu, MenuItem, MenuItemGroup, Tabs, TabPane, Breadcrumb, BreadcrumbItem, PageHeader, Dropdown, DropdownMenu, DropdownItem, Steps, Step |
| Notice | Alert, Loading, Message, MessageBox, Notification |
| Overlay | Dialog, Drawer, Tooltip, Popover, Popconfirm |
| Other | Card, Carousel, CarouselItem, Collapse, CollapseItem, Timeline, TimelineItem, Calendar, Image, Backtop, InfiniteScroll, Scrollbar, Spinner |
Note
Components like Message, Notification, MessageBox, and Loading are dual-mode: they can be used as template components AND as imperative service calls via
Vue.prototypemethods (this.$message,this.$notify,this.$msgbox,this.$loading).
Technology Stack
| Technology | Version | Role |
|---|---|---|
| Vue | ^2.5.17 | Peer dependency, runtime framework |
| async-validator | ~1.8.1 | Form validation engine |
| deepmerge | ^1.2.0 | Deep object merging (i18n, config) |
| normalize-wheel | ^1.0.1 | Cross-browser mousewheel normalization |
| resize-observer-polyfill | ^1.5.0 | ResizeObserver for responsive components |
| throttle-debounce | ^1.0.1 | Event throttling/debouncing |
| babel-helper-vue-jsx-merge-props | ^2.0.0 | JSX prop merging in render functions |
Data Flow
Vue.use(ElementUI, options)
│
├── locale.use(options.locale) ← Set language
├── locale.i18n(options.i18n) ← Set i18n handler
├── forEach component → Vue.component() ← Register all 67 components
├── Vue.use(InfiniteScroll) ← Register directive
├── Vue.use(Loading.directive) ← Register v-loading
└── Vue.prototype.$ELEMENT = { size, zIndex }
Vue.prototype.$loading = Loading.service
Vue.prototype.$msgbox = MessageBox
Vue.prototype.$alert = MessageBox.alert
Vue.prototype.$confirm = MessageBox.confirm
Vue.prototype.$prompt = MessageBox.prompt
Vue.prototype.$notify = Notification
Vue.prototype.$message = Message
2. System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Node.js | 10.x | 14.x+ |
| Vue | 2.5.17 | 2.6.x or 2.7.x |
| npm | 6.x | 8.x+ |
| Browsers | IE 10+ | Chrome, Firefox, Safari, Edge (latest) |
Runtime Dependencies
| Package | Version | Purpose |
|---|---|---|
async-validator |
~1.8.1 | Rule-based form validation |
babel-helper-vue-jsx-merge-props |
^2.0.0 | JSX support in render functions |
deepmerge |
^1.2.0 | Deep merge for locale + config objects |
normalize-wheel |
^1.0.1 | Normalize mousewheel events cross-browser |
resize-observer-polyfill |
^1.5.0 | ResizeObserver for Table, Scrollbar |
throttle-debounce |
^1.0.1 | Event rate limiting |
Dev/Build Dependencies (selected)
| Package | Version | Purpose |
|---|---|---|
webpack |
^4.14.0 | Module bundling |
babel-cli / babel-core |
^6.26.x | ES6+ transpilation |
node-sass / gulp-sass |
^4.x | SCSS compilation for theme-chalk |
karma / mocha / chai / sinon |
Various | Unit testing |
vue-loader |
^15.7.0 | Vue SFC compilation |
eslint |
4.18.2 | Linting with eslint-config-elemefe |
Important
node-sass(used for buildingtheme-chalk) is deprecated and may fail on Node 16+. If building themes locally, consider switching tosass(Dart Sass) or using the pre-built CSS fromlib/theme-chalk/.
3. Configuration Reference
Global Configuration Object
When calling Vue.use(ElementUI, options), the options object is stored on Vue.prototype.$ELEMENT:
| Key | Type | Default | Description |
|---|---|---|---|
size |
string |
'' |
Global component size. Values: 'medium', 'small', 'mini', '' (default). Affects all size-aware components. |
zIndex |
number |
2000 |
Base z-index for popup components (Dialog, Drawer, Popover, Tooltip, Select dropdown, etc.). Auto-incremented by PopupManager. |
Locale Configuration
| Method | Signature | Description |
|---|---|---|
locale.use(lang) |
use(langObject) |
Set the active language pack |
locale.i18n(fn) |
i18n(translatorFunction) |
Override the default translation handler |
The i18n function receives (key, options) where key is a dot-separated path (e.g., el.table.confirmFilter) and options is an interpolation object.
Environment Variables
| Variable | Context | Description |
|---|---|---|
NODE_ENV |
Build/Runtime | Controls development features. When 'production', the migrating mixin suppresses deprecation warnings |
VUE_ENV |
SSR test | Used in SSR test suite (test/ssr/) to configure server-side rendering |
PLAY_ENV |
Dev | When true, runs the playground dev server via npm run dev:play |
CI_ENV |
Test | Sets the base path for test resources in CI |
BABEL_ENV |
Build | Controls Babel preset selection (utils for lib build, test for test runs) |
Tip
The
migratingmixin (insrc/mixins/migrating.js) logs console warnings for deprecated props and events. These only run whenNODE_ENV !== 'production', so they help during development but have zero overhead in production.
Build Scripts
| Script | Command | Description |
|---|---|---|
dev |
npm run dev |
Start demo site with webpack-dev-server (port 8085) |
dev:play |
npm run dev:play |
Start playground dev server |
dist |
npm run dist |
Full production build (clean + lint + webpack + utils + UMD + theme) |
build:file |
npm run build:file |
Generate icon list, entry file, i18n files, version file |
build:theme |
npm run build:theme |
Compile SCSS → CSS via gulp, copy to lib/theme-chalk/ |
build:utils |
npm run build:utils |
Transpile src/ utilities to lib/ with Babel |
build:umd |
npm run build:umd |
Build UMD locale bundles |
test |
npm run test |
Lint + build theme + run karma unit tests |
test:watch |
npm run test:watch |
Run tests in watch mode |
lint |
npm run lint |
ESLint across src, test, packages, build |
pub |
npm run pub |
Publish: bootstrap + git release + npm release + algolia index |
Build Outputs
| Output | Path | Format | Description |
|---|---|---|---|
| Full bundle | lib/index.js |
UMD | Unpkg entry, all components |
| CommonJS bundle | lib/element-ui.common.js |
CJS | npm main field entry |
| Per-component | lib/{component}.js |
CJS | Individual component for tree-shaking |
| Utils | lib/utils/, lib/mixins/, lib/locale/, etc. |
CJS | Transpiled source utilities |
| Theme CSS | lib/theme-chalk/index.css |
CSS | Full compiled theme |
| Per-component CSS | lib/theme-chalk/{component}.css |
CSS | Individual component styles |
| UMD locales | lib/umd/locale/*.js |
UMD | Per-language packs for CDN |
| TypeScript | types/*.d.ts |
TS | Type declarations |
4. Deployment & Scaling
Distribution
Element UI is consumed as an npm package. It does not run as a service or require server deployment. Distribution considerations:
Full import (~700KB unminified JS + ~230KB CSS):
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Partial import (recommended for production):
Use babel-plugin-component to import only needed components and their styles. This can reduce the bundle to under 100KB for typical applications.
CDN deployment:
<link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.14/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui@2.15.14/lib/index.js"></script>
SSR Considerations
Element UI supports server-side rendering with Vue SSR. Key points:
- All service components (Message, Notification, MessageBox, Loading service) include
Vue.prototype.$isServerguards and no-op on the server - The popup manager skips z-index management on the server
- DOM utilities (
src/utils/dom.js) check fordocumentexistence before accessing it
Warning
The
v-loadingdirective andInfiniteScrolldirective access DOM APIs directly. When using Nuxt or other SSR frameworks, register Element UI as a client-only plugin.
Performance Optimization
| Strategy | How |
|---|---|
| Partial imports | Use babel-plugin-component for tree-shaking |
| Lazy-load tabs | Set lazy prop on <el-tab-pane> |
| Virtual scroll for tables | Use append slot with custom infinite-scroll logic |
| Image lazy loading | Set lazy prop on <el-image> |
| Skeleton loading | Use <el-skeleton> with throttle to avoid flash |
Table doLayout() |
Call after visibility changes to prevent layout thrash |
5. Operations
Theme Customization System
Element UI's theme is built with SCSS and lives in packages/theme-chalk/:
packages/theme-chalk/
├── src/
│ ├── common/
│ │ └── var.scss ← Master variable file (all design tokens)
│ ├── mixins/
│ │ ├── config.scss ← BEM naming configuration
│ │ ├── function.scss ← SCSS utility functions
│ │ └── mixins.scss ← Shared component mixins
│ ├── fonts/ ← Icon font files
│ ├── index.scss ← Main entry (imports all component styles)
│ ├── {component}.scss ← Per-component stylesheet
│ └── date-picker/*.scss ← Date picker sub-styles
├── gulpfile.js ← Build: sass → autoprefixer → cssmin → lib/
└── package.json ← Published as `element-theme-chalk`
Key theme variables (from src/common/var.scss):
| Variable | Default | Controls |
|---|---|---|
$--color-primary |
#409EFF |
Primary brand color |
$--color-success |
#67C23A |
Success state color |
$--color-warning |
#E6A23C |
Warning state color |
$--color-danger |
#F56C6C |
Danger/error state color |
$--color-info |
#909399 |
Info state color |
$--color-text-primary |
#303133 |
Primary text |
$--color-text-regular |
#606266 |
Regular text |
$--font-size-base |
14px |
Base font size |
$--border-radius-base |
4px |
Default border radius |
$--border-color-base |
#DCDFE6 |
Default border color |
Theme build pipeline:
# In packages/theme-chalk/
gulp build
# Steps: sass → autoprefixer → cssmin → lib/
Note
The theme uses BEM naming convention:
el-{component},el-{component}__{element},el-{component}--{modifier}. The$namespacedefaults toel.
Online Theme Editor
The demo site includes a theme configurator at examples/components/theme-configurator/. It allows:
- Live editing of SCSS variables
- Real-time preview of component styles
- Download of compiled custom theme
- Local storage persistence of user theme configs
Theme constants are stored via ELEMENT_THEME_USER_CONFIG and ELEMENT_THEME_PREVIEW_CONFIG localStorage keys.
i18n System
Architecture:
src/locale/
├── index.js ← Locale engine: use(), i18n(), t()
├── format.js ← String template interpolation
└── lang/ ← 50+ language packs (zh-CN, en, es, fr-FR, ja, ko, etc.)
How translation works:
- Each component uses the
localemixin which providesthis.t(key, options) t()first tries the customi18nhandler (if registered vialocale.i18n(fn))- Falls back to dot-path lookup in the active language pack
- Interpolates
{placeholders}via the format engine
Supported languages include: zh-CN (default), zh-TW, en, es, fr, de, ja, ko, pt, pt-br, ru, ar, it, nl, pl, sv, tr, vi, th, and 30+ more.
Tip
To add a new language, create a new file in
src/locale/lang/following the structure of any existing pack. The keys match theel.*namespace used throughout components.
Popup and Z-Index Management
The PopupManager (src/utils/popup/popup-manager.js) manages global z-index ordering for all overlay components:
- Base z-index starts from
Vue.prototype.$ELEMENT.zIndex(default 2000) - Each popup increments the global counter via
PopupManager.nextZIndex() - Modals register/deregister for body scroll locking
- The manager tracks a stack of open modals for correct ESC-key handling
6. Performance
Bundle Size
| Bundle | Size (approx.) |
|---|---|
lib/index.js (UMD, unminified) |
~700KB |
lib/element-ui.common.js (CJS) |
~680KB |
lib/theme-chalk/index.css |
~230KB |
| Minified + gzipped (full) | ~90KB JS + ~45KB CSS |
Partial imports can significantly reduce this. A typical app using 15-20 components may end up with ~150KB total (minified + gzipped).
Table Performance
The Table component (packages/table/src/) is the most complex component at 91KB of source across 12 files. Performance considerations:
- Fixed columns create shadow DOM copies of the table, doubling render cost
- Large datasets (1000+ rows) benefit from fixed
heightwhich enables virtual scrolling doLayout()should be called after visibility changes (tab switches, accordion opens) to recalculate column widths- Memory leaks can occur if tables are shown/hidden with
v-showinstead ofv-if— the layout observers may not clean up (issue #22980)
Note
The Table component uses a dedicated Vuex-like store (
packages/table/src/store/) to manage column state, sorting, filtering, expansion, and selection. Each Table instance gets its own store.
Rendering Optimizations Built In
- Throttled scroll handlers in Table and InfiniteScroll via
throttle-debounce - ResizeObserver polyfill for responsive Table columns and Scrollbar
- Lazy rendering for TabPane (
lazyprop) and Image (lazyprop) - Virtual scrolling in Scrollbar component
- Transition caching via the CollapseTransition component
- Mouse event normalization via
normalize-wheelfor consistent scroll behavior
7. Security
XSS Prevention
Several components support dangerouslyUseHTMLString for rendering raw HTML:
| Component | Prop | Default |
|---|---|---|
| Message | dangerouslyUseHTMLString |
false |
| Notification | dangerouslyUseHTMLString |
false |
| MessageBox | dangerouslyUseHTMLString |
false |
Caution
When
dangerouslyUseHTMLStringis set totrue, the content is rendered viav-html. Never pass unsanitized user input through these options. Always sanitize HTML before rendering to prevent cross-site scripting attacks.
Dependency Security
| Concern | Detail |
|---|---|
| lodash (devDependency) | Version 4.17.17 has known prototype pollution vulnerabilities. Upgrade to 4.17.21+ if using the build system (issues #23127, #23132) |
| node-sass (devDependency) | Deprecated; binary downloads may fail on newer OS/Node combinations. Consider migrating theme builds to Dart Sass |
| async-validator 1.8.x | Pinned to legacy version. Later versions changed validation behavior |
Content Security Policy
Element UI injects styles dynamically for:
- Loading overlay positioning
- Theme configurator live preview
- Popup z-index management
If your application enforces strict CSP (style-src without 'unsafe-inline'), the Loading directive's inline style injection will fail. Use the service API with pre-defined classes instead.
8. Developer Internals
Repository Structure
.
├── build/ ← Build scripts and webpack configs
│ ├── bin/
│ │ ├── build-entry.js ← Auto-generates src/index.js from components.json
│ │ ├── iconInit.js ← Generates icon list from theme-chalk
│ │ ├── i18n.js ← Generates i18n page data
│ │ ├── version.js ← Writes version file
│ │ ├── gen-cssfile.js ← Generates per-component CSS imports
│ │ └── build-locale.js ← Builds UMD locale bundles
│ ├── webpack.conf.js ← UMD full bundle config
│ ├── webpack.common.js ← CommonJS full bundle config
│ ├── webpack.component.js ← Per-component CommonJS bundles
│ └── webpack.demo.js ← Demo site dev server config
├── examples/ ← Demo website (Vue SPA)
│ ├── app.vue ← Root component
│ ├── entry.js ← Webpack entry
│ ├── route.config.js ← Router (loads doc pages from examples/docs/)
│ ├── nav.config.json ← Navigation structure
│ ├── docs/ ← Markdown documentation (zh-CN, en-US, es, fr-FR)
│ ├── components/ ← Theme editor, search, demo components
│ └── i18n/ ← Demo site i18n (page titles, labels)
├── packages/ ← Component packages (67+)
│ ├── {component}/
│ │ ├── index.js ← Package entry: imports + sets install()
│ │ └── src/
│ │ ├── main.vue ← Component implementation (SFC)
│ │ └── *.js ← Supporting logic
│ └── theme-chalk/ ← SCSS theme package
├── src/ ← Shared infrastructure
│ ├── index.js ← Master entry (auto-generated)
│ ├── mixins/ ← Shared component behaviors
│ ├── directives/ ← Internal directives
│ ├── locale/ ← i18n engine + language packs
│ ├── transitions/ ← Animation components
│ └── utils/ ← Utility library (17 files, ~100KB)
├── test/ ← Test suites
│ ├── unit/ ← Karma + Mocha unit tests
│ │ ├── karma.conf.js ← Karma configuration
│ │ ├── index.js ← Test entry (requires all spec files)
│ │ ├── specs/ ← Per-component test specs
│ │ └── mocks/ ← Test mocks
│ └── ssr/ ← Server-side rendering tests
├── types/ ← TypeScript declarations
│ ├── index.d.ts ← Master type entry
│ ├── element-ui.d.ts ← Main module types
│ └── {component}.d.ts ← Per-component types
├── components.json ← Component registry (name → path mapping)
├── web-types.json ← JetBrains IDE component metadata
├── package.json ← Package manifest
├── Makefile ← Build shortcuts
└── .travis.yml ← CI configuration (Node 10, Chrome)
Component Architecture Pattern
Every component follows the same pattern:
1. Package entry (packages/{name}/index.js):
import Component from './src/main';
Component.install = function(Vue) {
Vue.component(Component.name, Component);
};
export default Component;
2. Component SFC (packages/{name}/src/main.vue):
- Uses
componentName(internal) for the emitter mixin's dispatch/broadcast - Injects parent context where needed (e.g.,
inject: ['elForm']) - Provides context to children (e.g.,
provide() { return { elFormItem: this } }) - Uses the
localemixin forthis.t()translations - Uses the
emittermixin for cross-component communication - Uses the
migratingmixin for deprecation warnings
3. Service components (Message, Notification, Loading, MessageBox) follow a constructor pattern:
const Constructor = Vue.extend(MainComponent);
const instance = new Constructor({ data: options });
instance.$mount();
document.body.appendChild(instance.$el);
Mixin System
| Mixin | File | Purpose |
|---|---|---|
emitter |
src/mixins/emitter.js |
Cross-component event dispatch (up) and broadcast (down) by componentName |
focus |
src/mixins/focus.js |
Factory that returns a mixin adding focus() method targeting a $ref |
locale |
src/mixins/locale.js |
Adds this.t() for i18n translations |
migrating |
src/mixins/migrating.js |
Logs deprecation warnings for renamed props/events (dev only) |
The emitter mixin is critical infrastructure — it replaces Vue's removed $dispatch and $broadcast by walking the component tree via $parent / $children and matching on componentName.
Utility Library
The src/utils/ directory (17 files, ~100KB) provides:
| Module | Purpose |
|---|---|
dom.js |
DOM manipulation: addClass, removeClass, getStyle, setStyle, on, off, once |
util.js |
General utilities: generateId, kebabCase, getPropByPath, escapeRegexpString, isIE, isMac |
date.js |
Date formatting/parsing (fecha library fork) |
types.js |
Type checking: isString, isObject, isHtmlElement, isFunction, isDefined, isUndefined, isKorean |
merge.js |
Object merge utility |
vdom.js |
VNode utilities: isVNode |
resize-event.js |
ResizeObserver-based element resize detection |
scrollbar-width.js |
Native scrollbar width measurement |
scroll-into-view.js |
Scroll element into visible area |
clickoutside.js |
Click-outside directive implementation |
after-leave.js |
Callback after CSS transition leave |
aria-dialog.js |
ARIA dialog accessibility utilities |
aria-utils.js |
Focus trap and ARIA attribute management |
popper.js |
Popper.js v1 (vendored, ~30KB) for tooltip/popover positioning |
popup/ |
Popup manager: z-index management, modal stacking, body scroll locking |
Error Messages Reference
The following error messages are thrown from source code:
| Error | Source | Cause |
|---|---|---|
Can not find table layout. |
packages/table/src/layout-observer.js:17 |
TableColumn used outside Table |
for nested data item, row-key is required. |
packages/table/src/table-body.js:432 |
Tree data without row-key |
table is required for Table Layout |
packages/table/src/table-layout.js:36 |
TableLayout instantiated without table ref |
store is required for Table Layout |
packages/table/src/table-layout.js:39 |
TableLayout instantiated without store ref |
Table Layout don't have this column |
packages/table/src/table-layout.js:243 |
Column reference mismatch |
row is required when get row identity |
packages/table/src/util.js:108 |
getRowIdentity called with null row |
instance & callback is required |
src/utils/after-leave.js:10 |
afterLeave called without required args |
Dialog() requires a DOM element with ARIA role of dialog. |
src/utils/aria-dialog.js:26 |
ARIA dialog utility passed non-dialog element |
Invalid Date in fecha.format |
src/utils/date.js:267 |
Invalid date passed to formatter |
Invalid format in fecha.parse |
src/utils/date.js:300 |
Invalid format string for date parsing |
className should not contain space. |
src/utils/dom.js:69 |
Multiple classes in single addClass call |
Cannot convert first argument to object |
src/utils/popper.js:1250 |
Invalid reference element for Popper |
please transfer a valid prop path to form item! |
src/utils/util.js:61 |
Invalid prop path on FormItem |
Directives
Public directives (registered via Vue.use):
| Directive | Description |
|---|---|
v-loading |
Show loading overlay. Modifiers: .body (append to body), .fullscreen, .lock (prevent scroll). Attributes: element-loading-text, element-loading-spinner, element-loading-background, element-loading-custom-class |
v-infinite-scroll |
Trigger function when scrolling to bottom. Attributes: infinite-scroll-disabled, infinite-scroll-delay, infinite-scroll-distance, infinite-scroll-immediate |
v-popover |
Associate a trigger element with a named Popover instance |
Internal directives (not publicly registered):
| Directive | File | Purpose |
|---|---|---|
v-mousewheel |
src/directives/mousewheel.js |
Normalized mousewheel events (Firefox DOMMouseScroll handling) |
v-repeat-click |
src/directives/repeat-click.js |
Repeated action on mousedown hold (used in InputNumber, Slider) |
v-clickoutside |
src/utils/clickoutside.js |
Close popups on outside click |
Testing Strategy
Framework: Karma + Mocha + Chai + Sinon
Configuration: test/unit/karma.conf.js configures Chrome headless, webpack preprocessing, Istanbul coverage, and spec reporter.
Test entry: test/unit/index.js requires all *.spec.js files from test/unit/specs/.
Coverage: Istanbul instrumentation via babel-plugin-istanbul, output to test/unit/coverage/.
SSR tests: test/ssr/require.test.js verifies that all components can be required in a Node.js environment without DOM errors.
Running tests:
# Full test suite (lint + build theme + karma)
npm test
# Watch mode (auto-rerun on changes)
npm run test:watch
Note
Tests require Chrome (via
karma-chrome-launcher). The.travis.ymlconfiguresaddons: chrome: stablefor CI.
Code Patterns and Conventions
BEM naming: All CSS classes follow el-{block}__{element}--{modifier} pattern.
Component naming: PascalCase in JS (ElButton), kebab-case in templates (<el-button>). Internal componentName property used by the emitter mixin.
JSX render functions: Table, Select, Autocomplete, and several other complex components use JSX render functions (via babel-plugin-transform-vue-jsx) instead of templates for dynamic rendering.
Component communication:
- Parent → Child: props
- Child → Parent:
$emitevents - Cross-level:
emittermixin'sdispatch(bubbles up to named ancestor) andbroadcast(propagates down to named descendant) - Dependency injection:
provide/injectfor Form → FormItem, Select → Option, etc.
Auto-generated files:
src/index.js— generated bybuild/bin/build-entry.jsfromcomponents.json- Icon list — generated by
build/bin/iconInit.jsfrom theme-chalk icon font - i18n pages — generated by
build/bin/i18n.js
Potential Improvements
Based on the current codebase and community issues:
- Upgrade lodash to 4.17.21+ — current devDependency has known prototype pollution vulnerabilities (issues #23127, #23132)
- Migrate from node-sass to Dart Sass —
node-sassis deprecated and causes build failures on modern Node versions - Table memory leak mitigation — ResizeObserver and event listeners in Table may not properly clean up (issue #22980)
- Fixed column + summary scrollbar fix — Known interaction bug between fixed columns and summary row (issues #23142, #20515)
- Upgrade async-validator — Pinned to ~1.8.1; newer versions include important fixes but may change validation behavior
- Babel 6 → 7 migration — Build toolchain uses Babel 6 which is EOL
- Webpack 4 → 5 migration — Webpack 4 is in maintenance mode
9. Integration Points
Vue Router Integration
The <el-menu> component supports router mode — setting router prop causes menu items to navigate using their index as the route path:
<el-menu router :default-active="$route.path">
<el-menu-item index="/dashboard">Dashboard</el-menu-item>
<el-menu-item index="/settings">Settings</el-menu-item>
</el-menu>
<el-breadcrumb-item> supports the :to prop for Vue Router navigation.
vue-i18n Integration
Element UI integrates with vue-i18n through the i18n install option. The handler receives the translation key and interpolation options, allowing Element UI's internal translations to merge with your application's translations.
Form Validation (async-validator)
Element UI's Form component uses async-validator v1.8.x for validation rules. Rules support:
| Rule Property | Description |
|---|---|
required |
Field is required |
type |
Value type: string, number, boolean, email, url, array, etc. |
min / max |
Length constraints (string) or value constraints (number) |
pattern |
Regular expression match |
validator |
Custom validation function: (rule, value, callback) => {} |
trigger |
When to validate: 'blur', 'change', or array of both |
message |
Error message string |
TypeScript Support
Type declarations ship in the types/ directory:
import Vue from 'vue';
import ElementUI from 'element-ui';
Vue.use(ElementUI);
// Component types
import { ElButton } from 'element-ui/types/button';
// Service types
import { ElMessageBox } from 'element-ui/types/message-box';
The types/index.d.ts augments Vue with the $ELEMENT, $message, $notify, $msgbox, $alert, $confirm, $prompt, and $loading prototype methods.
JetBrains IDE Support
The web-types.json file at the package root provides component metadata (props, events, slots, descriptions) for JetBrains IDEs (WebStorm, IntelliJ). This enables auto-completion and inline documentation for all Element UI components.
Tip
VS Code users can get similar auto-completion through the Vetur extension, which reads component type definitions and the
web-types.jsonfile.