Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Element UI User Guide

Generated June 2026 from ElemeFE/element at c345bb4

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Quick Start

Element UI is a Vue 2.x component library providing 67+ production-ready UI components for building web applications. Developed by the Ele.me frontend team, it offers a complete design system with consistent styling, internationalization, and theme customization.

Key features:

  • 67+ components covering forms, data display, navigation, feedback, and layout
  • Built-in i18n with 50+ language packs
  • Customizable theme system via SCSS variables
  • TypeScript type definitions included
  • Vue Router integration for navigation components
  • Service-based components (Message, Notification, MessageBox, Loading)
  • Responsive grid system with 5 breakpoints
  • Form validation powered by async-validator

Prerequisites: Node.js 10+, Vue 2.5.17+

Install and verify:

npm install element-ui
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

What to try next: See Installation for all methods, Configuration for global options, or jump to Core Usage for component examples.

2. Installation

System Requirements

Requirement Version
Node.js 10+
Vue ^2.5.17
npm / yarn Any recent

Install Methods

npm

npm install element-ui

yarn

yarn add element-ui

CDN

<!-- CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- JS -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

Tip

The CDN approach is the fastest way to prototype. Element UI auto-installs itself when it detects window.Vue.

Full Import

Register all components globally:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

Partial Import

Import only the components you need to reduce bundle size. Use babel-plugin-component for automatic style imports:

npm install babel-plugin-component --save-dev

Configure .babelrc:

{
  "plugins": [
    ["component", {
      "libraryName": "element-ui",
      "styleLibraryName": "theme-chalk"
    }]
  ]
}

Then import individual components:

import { Button, Select, Table } from 'element-ui';

Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
Vue.component(Table.name, Table);

Important

When using partial imports, you must still manually register service components if needed: Vue.prototype.$message = Message; and Vue.use(Loading.directive);.

Post-Install Verification

import ElementUI from 'element-ui';
console.log(ElementUI.version);
2.15.14

Install Troubleshooting

Error: node-sass build failure

Cause: node-sass is a devDependency of Element UI's theme package and can fail on newer Node versions.

Solution:

  1. Use npm install --ignore-scripts if you don't need to rebuild themes
  2. Or install the pre-built CSS from element-ui/lib/theme-chalk/index.css

Error: Module not found: element-ui

Cause: Package not installed or incorrect import path.

Solution:

npm install element-ui --save

Error: Components render without styles

Cause: Missing CSS import.

Solution:

import 'element-ui/lib/theme-chalk/index.css';

Error: Vue is not a constructor or Cannot read property 'use' of undefined

Cause: Vue 3 project trying to use Element UI (which requires Vue 2).

Solution: Element UI only supports Vue 2.x. For Vue 3, use Element Plus instead.

3. Configuration

Global Configuration

Pass options to Vue.use() to configure all components:

Vue.use(ElementUI, {
  size: 'small',    // Component size: 'medium' | 'small' | 'mini'
  zIndex: 3000,     // Starting z-index for popups (default: 2000)
  locale: enLocale, // Language pack
  i18n: fn          // Custom i18n handler
});
Option Type Default Description
size string '' Global component size: 'medium', 'small', 'mini'
zIndex number 2000 Starting z-index for popup-based components
locale object zh-CN Language pack object
i18n function null Custom i18n translation function

Note

The global size and zIndex are stored on Vue.prototype.$ELEMENT and can be accessed from any component instance.

Internationalization (i18n)

Element UI defaults to Chinese (zh-CN). Switch to English or other languages:

import lang from 'element-ui/lib/locale/lang/en';
import locale from 'element-ui/lib/locale';

locale.use(lang);

With vue-i18n:

import Vue from 'vue';
import VueI18n from 'vue-i18n';
import ElementUI from 'element-ui';
import enLocale from 'element-ui/lib/locale/lang/en';
import zhLocale from 'element-ui/lib/locale/lang/zh-CN';

Vue.use(VueI18n);

const i18n = new VueI18n({
  locale: 'en',
  messages: {
    en: { ...enLocale },
    zh: { ...zhLocale }
  }
});

Vue.use(ElementUI, { i18n: (key, value) => i18n.t(key, value) });

Tip

Element UI includes 50+ language packs in element-ui/lib/locale/lang/. Check the src/locale/lang/ directory for the full list.

For full configuration reference, see the Admin Guide.

4. Core Usage

Basic Components

Button

Buttons support types, sizes, icons, loading state, and grouping:

<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
<el-button type="success" icon="el-icon-check">Success</el-button>
<el-button type="danger" round>Rounded</el-button>
<el-button type="warning" circle icon="el-icon-star-off"></el-button>
<el-button :loading="true">Loading</el-button>
Prop Type Default Description
type string — 'primary', 'success', 'warning', 'danger', 'info', 'text'
size string — 'medium', 'small', 'mini'
plain boolean false Plain style
round boolean false Round corners
circle boolean false Circle shape
loading boolean false Show loading spinner
disabled boolean false Disable the button
icon string — Icon class name
nativeType string 'button' Native type: 'button', 'submit', 'reset'

Icon

Element UI provides a built-in icon set. Use icon names with the el-icon- prefix:

<i class="el-icon-edit"></i>
<i class="el-icon-share"></i>
<i class="el-icon-delete"></i>

<!-- In buttons -->
<el-button icon="el-icon-search">Search</el-button>

Text hyperlink component:

<el-link href="https://example.com" target="_blank" type="primary">Link</el-link>
<el-link :underline="false">No Underline</el-link>
<el-link disabled>Disabled</el-link>

Layout

Container System

Build page layouts with semantic container components:

<el-container>
  <el-header height="60px">Header</el-header>
  <el-container>
    <el-aside width="200px">Sidebar</el-aside>
    <el-main>Content</el-main>
  </el-container>
  <el-footer height="60px">Footer</el-footer>
</el-container>

Note

When <el-container> contains <el-header> or <el-footer>, its children arrange vertically. Otherwise they arrange horizontally. Override with the direction prop.

Grid System (Row / Col)

A responsive 24-column grid:

<el-row :gutter="20">
  <el-col :span="6"><div>col-6</div></el-col>
  <el-col :span="6"><div>col-6</div></el-col>
  <el-col :span="6"><div>col-6</div></el-col>
  <el-col :span="6"><div>col-6</div></el-col>
</el-row>

<!-- Responsive -->
<el-row>
  <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4">
    <div>Responsive column</div>
  </el-col>
</el-row>

Row props:

Prop Type Default Description
gutter number 0 Grid spacing in pixels
type string — Set to 'flex' for flexbox mode
justify string — Flex horizontal alignment
align string — Flex vertical alignment

Col responsive breakpoints:

Prop Breakpoint
xs <768px
sm ≥768px
md ≥992px
lg ≥1200px
xl ≥1920px

Form Components

Input

<el-input v-model="text" placeholder="Enter text"></el-input>

<!-- Textarea -->
<el-input type="textarea" :rows="4" v-model="content"></el-input>

<!-- With icon -->
<el-input prefix-icon="el-icon-search" v-model="search"></el-input>

<!-- Clearable -->
<el-input v-model="text" clearable></el-input>

<!-- Password toggle -->
<el-input v-model="password" show-password></el-input>

<!-- Word limit -->
<el-input v-model="text" maxlength="100" show-word-limit></el-input>
Prop Type Default Description
type string 'text' Input type: 'text', 'textarea', or native types
v-model string/number — Binding value
placeholder string — Placeholder text
clearable boolean false Show clear button
show-password boolean false Toggle password visibility
show-word-limit boolean false Show word count (requires maxlength)
disabled boolean false Disable input
size string — 'medium', 'small', 'mini'
prefix-icon string — Prefix icon class
suffix-icon string — Suffix icon class
autosize boolean/object false Auto-resize textarea: true or { minRows: 2, maxRows: 6 }

Slots: prefix, suffix, prepend, append

InputNumber

<el-input-number v-model="num" :min="1" :max="100" :step="2"></el-input-number>

Select

<el-select v-model="value" placeholder="Select">
  <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value">
  </el-option>
</el-select>

<!-- Multiple selection -->
<el-select v-model="values" multiple placeholder="Select">
  <el-option v-for="item in options" :key="item.value"
    :label="item.label" :value="item.value">
  </el-option>
</el-select>

<!-- Filterable -->
<el-select v-model="value" filterable placeholder="Search">
  <el-option v-for="item in options" :key="item.value"
    :label="item.label" :value="item.value">
  </el-option>
</el-select>

<!-- Remote search -->
<el-select v-model="value" filterable remote :remote-method="search"
  :loading="loading" placeholder="Search">
  <el-option v-for="item in results" :key="item.value"
    :label="item.label" :value="item.value">
  </el-option>
</el-select>
Prop Type Default Description
v-model any — Binding value
multiple boolean false Enable multi-select
filterable boolean false Enable search filtering
remote boolean false Enable remote search
remote-method function — Remote search function
clearable boolean false Show clear button
allow-create boolean false Allow creating new items (requires filterable)
multiple-limit number 0 Max selections (0 = unlimited)
collapse-tags boolean false Collapse tags in multi-select
default-first-option boolean false Select first match on Enter

Tip

Group options with <el-option-group> by wrapping related <el-option> elements and setting a label prop on the group.

Radio and Checkbox

<!-- Radio -->
<el-radio-group v-model="radio">
  <el-radio :label="1">Option A</el-radio>
  <el-radio :label="2">Option B</el-radio>
</el-radio-group>

<!-- Radio buttons -->
<el-radio-group v-model="radio">
  <el-radio-button label="Option A"></el-radio-button>
  <el-radio-button label="Option B"></el-radio-button>
</el-radio-group>

<!-- Checkbox -->
<el-checkbox-group v-model="checked">
  <el-checkbox label="Option A"></el-checkbox>
  <el-checkbox label="Option B"></el-checkbox>
</el-checkbox-group>

Switch

<el-switch v-model="active"></el-switch>

<!-- Custom values and colors -->
<el-switch v-model="value"
  active-color="#13ce66"
  inactive-color="#ff4949"
  active-value="on"
  inactive-value="off">
</el-switch>

Slider

<el-slider v-model="value"></el-slider>

<!-- Range -->
<el-slider v-model="range" range :min="0" :max="100"></el-slider>

<!-- With input box -->
<el-slider v-model="value" show-input></el-slider>

DatePicker and TimePicker

<!-- Date -->
<el-date-picker v-model="date" type="date" placeholder="Pick a date">
</el-date-picker>

<!-- Date range -->
<el-date-picker v-model="dateRange" type="daterange"
  start-placeholder="Start" end-placeholder="End">
</el-date-picker>

<!-- DateTime -->
<el-date-picker v-model="datetime" type="datetime"
  placeholder="Pick date and time">
</el-date-picker>

<!-- Time picker -->
<el-time-picker v-model="time" placeholder="Pick time">
</el-time-picker>

<!-- Time select (fixed intervals) -->
<el-time-select v-model="time" placeholder="Pick time"
  :picker-options="{ start: '08:00', step: '00:30', end: '18:00' }">
</el-time-select>
DatePicker type Description
date Single date
daterange Date range
datetime Date with time
datetimerange DateTime range
week Week picker
month Month picker
monthrange Month range
year Year picker

Warning

The firstDayOfWeek option in picker-options has known issues when used with type="week" (see issue #23126). Test thoroughly if your application requires non-default week start days.

Upload

<el-upload action="https://api.example.com/upload"
  :on-success="handleSuccess"
  :on-error="handleError"
  :limit="3"
  :on-exceed="handleExceed">
  <el-button type="primary">Click to Upload</el-button>
  <div slot="tip" class="el-upload__tip">Only jpg/png files, max 500KB</div>
</el-upload>

<!-- Drag-and-drop -->
<el-upload action="https://api.example.com/upload" drag multiple>
  <i class="el-icon-upload"></i>
  <div class="el-upload__text">Drop files here or <em>click to upload</em></div>
</el-upload>
Prop Type Default Description
action string required Upload endpoint URL
multiple boolean false Allow multiple files
drag boolean false Enable drag-and-drop
accept string — Accepted file types
limit number — Max file count
auto-upload boolean true Upload immediately on select
list-type string 'text' 'text', 'picture', 'picture-card'
headers object — Request headers
data object — Additional form data
with-credentials boolean false Send cookies
http-request function — Override default upload behavior

Cascader

Hierarchical selection for data with parent-child relationships:

<el-cascader v-model="value" :options="options" :props="{ expandTrigger: 'hover' }">
</el-cascader>

<!-- Filterable -->
<el-cascader v-model="value" :options="options" filterable></el-cascader>

ColorPicker

<el-color-picker v-model="color"></el-color-picker>
<el-color-picker v-model="color" show-alpha></el-color-picker>

Transfer

Dual-list selection for moving items between two panels:

<el-transfer v-model="selected" :data="data"
  :titles="['Available', 'Selected']" filterable>
</el-transfer>

Rate

<el-rate v-model="score"></el-rate>
<el-rate v-model="score" show-text :texts="['Bad','Poor','Normal','Good','Great']"></el-rate>

Form Validation

Combine <el-form> with validation rules powered by async-validator:

<el-form :model="form" :rules="rules" ref="form" label-width="120px">
  <el-form-item label="Name" prop="name">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  <el-form-item label="Email" prop="email">
    <el-input v-model="form.email"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm">Submit</el-button>
    <el-button @click="resetForm">Reset</el-button>
  </el-form-item>
</el-form>
export default {
  data() {
    return {
      form: { name: '', email: '' },
      rules: {
        name: [
          { required: true, message: 'Name is required', trigger: 'blur' },
          { min: 3, max: 50, message: 'Length must be 3-50', trigger: 'blur' }
        ],
        email: [
          { required: true, message: 'Email is required', trigger: 'blur' },
          { type: 'email', message: 'Invalid email format', trigger: ['blur', 'change'] }
        ]
      }
    };
  },
  methods: {
    submitForm() {
      this.$refs.form.validate(valid => {
        if (valid) { /* submit */ }
      });
    },
    resetForm() {
      this.$refs.form.resetFields();
    }
  }
};

Form methods:

Method Description
validate(callback) Validate entire form. Callback receives (valid, failedFields)
validateField(props, callback) Validate specific field(s)
resetFields() Reset all fields and clear validation
clearValidate(props?) Clear validation messages

Important

The prop attribute on <el-form-item> must match a key in the form's :model object. Nested paths use colon notation: prop="address:city".

Data Display

Table

<el-table :data="tableData" style="width: 100%">
  <el-table-column prop="name" label="Name" width="180"></el-table-column>
  <el-table-column prop="email" label="Email"></el-table-column>
  <el-table-column prop="date" label="Date" sortable></el-table-column>
  <el-table-column label="Actions">
    <template slot-scope="scope">
      <el-button size="mini" @click="handleEdit(scope.row)">Edit</el-button>
      <el-button size="mini" type="danger" @click="handleDelete(scope.row)">Delete</el-button>
    </template>
  </el-table-column>
</el-table>

Key Table features:

Feature How to enable
Striped rows stripe prop on <el-table>
Border border prop
Fixed height + scroll height or max-height prop
Fixed columns fixed prop on <el-table-column> (true, 'left', 'right')
Sorting sortable prop on column (true or 'custom')
Filtering filters + filter-method props on column
Selection Column with type="selection"
Expand row Column with type="expand" + scoped slot
Summary row show-summary prop on table
Row index Column with type="index"
Row highlight highlight-current-row prop
Tree data row-key + tree-structured data + lazy + load

Warning

When using fixed columns with show-summary, the scrollbar may not work correctly (known issue #23142, #20515). Test with your specific data layout.

Tag

<el-tag>Default</el-tag>
<el-tag type="success">Success</el-tag>
<el-tag type="warning">Warning</el-tag>
<el-tag type="danger">Danger</el-tag>
<el-tag closable @close="handleClose">Closable</el-tag>

Badge

<el-badge :value="12">
  <el-button>Comments</el-button>
</el-badge>
<el-badge :value="200" :max="99">
  <el-button>Replies</el-button>
</el-badge>
<el-badge is-dot>
  <el-button>Notifications</el-button>
</el-badge>

Tree

<el-tree :data="data" :props="{ children: 'children', label: 'label' }"
  show-checkbox node-key="id"
  @check-change="handleCheckChange">
</el-tree>

Tree supports lazy loading, drag-and-drop (draggable), custom node content via scoped slots, filtering, and accordion mode.

Tip

Set node-key to a unique identifier in your data for reliable programmatic access to nodes via methods like getCheckedKeys(), setCheckedKeys(), and getNode().

Pagination

<el-pagination
  @size-change="handleSizeChange"
  @current-change="handlePageChange"
  :current-page="currentPage"
  :page-sizes="[10, 20, 50, 100]"
  :page-size="20"
  layout="total, sizes, prev, pager, next, jumper"
  :total="400">
</el-pagination>

The layout prop controls which elements appear: sizes, prev, pager, next, jumper, -> (right-align separator), total, slot.

Progress

<el-progress :percentage="50"></el-progress>
<el-progress :percentage="75" status="success"></el-progress>
<el-progress :percentage="80" :stroke-width="18" text-inside></el-progress>
<el-progress type="circle" :percentage="60"></el-progress>
<el-progress type="dashboard" :percentage="80"></el-progress>

Descriptions

Display multiple fields in a list layout:

<el-descriptions title="User Info" :column="3" border>
  <el-descriptions-item label="Name">John Doe</el-descriptions-item>
  <el-descriptions-item label="Email">[email removed]</el-descriptions-item>
  <el-descriptions-item label="Role">Admin</el-descriptions-item>
</el-descriptions>

Skeleton

Loading placeholder while data fetches:

<el-skeleton :loading="loading" animated :rows="5">
  <template slot="template">
    <el-skeleton-item variant="h1" style="width: 50%" />
    <el-skeleton-item variant="text" />
    <el-skeleton-item variant="text" />
    <el-skeleton-item variant="text" style="width: 60%" />
  </template>
  <template>
    <!-- Actual content here -->
  </template>
</el-skeleton>

Statistic

Display a statistic with optional prefix/suffix:

<el-statistic :value="268500" title="Active Users"></el-statistic>

Empty and Result

<el-empty description="No data available"></el-empty>

<el-result icon="success" title="Success" sub-title="Your operation completed">
  <template slot="extra">
    <el-button type="primary">Back</el-button>
  </template>
</el-result>

Avatar

<el-avatar src="https://example.com/avatar.jpg"></el-avatar>
<el-avatar icon="el-icon-user-solid"></el-avatar>
<el-avatar :size="50" shape="square">User</el-avatar>

Calendar

<el-calendar v-model="date"></el-calendar>
<!-- Horizontal -->
<el-menu mode="horizontal" :default-active="activeIndex" @select="handleSelect">
  <el-menu-item index="1">Home</el-menu-item>
  <el-submenu index="2">
    <template slot="title">Products</template>
    <el-menu-item index="2-1">Product A</el-menu-item>
    <el-menu-item index="2-2">Product B</el-menu-item>
  </el-submenu>
  <el-menu-item index="3">About</el-menu-item>
</el-menu>

<!-- Vertical with collapse -->
<el-menu :default-active="activeIndex" :collapse="isCollapsed">
  <el-menu-item index="1"><i class="el-icon-house"></i><span>Home</span></el-menu-item>
  <el-submenu index="2">
    <template slot="title"><i class="el-icon-setting"></i><span>Settings</span></template>
    <el-menu-item index="2-1">General</el-menu-item>
    <el-menu-item index="2-2">Security</el-menu-item>
  </el-submenu>
</el-menu>

Enable Vue Router integration by adding the router prop — menu items use their index as the route path.

Tabs

<el-tabs v-model="activeTab" type="card" @tab-click="handleClick">
  <el-tab-pane label="Tab 1" name="first">Content 1</el-tab-pane>
  <el-tab-pane label="Tab 2" name="second">Content 2</el-tab-pane>
  <el-tab-pane label="Tab 3" name="third" lazy>Content 3 (lazy)</el-tab-pane>
</el-tabs>

Tab types: default (no type), card, border-card. Positions: top (default), right, bottom, left.

<el-breadcrumb separator="/">
  <el-breadcrumb-item :to="{ path: '/' }">Home</el-breadcrumb-item>
  <el-breadcrumb-item>Products</el-breadcrumb-item>
  <el-breadcrumb-item>Detail</el-breadcrumb-item>
</el-breadcrumb>

Steps

<el-steps :active="active" finish-status="success">
  <el-step title="Step 1" description="Description"></el-step>
  <el-step title="Step 2"></el-step>
  <el-step title="Step 3"></el-step>
</el-steps>

Supports direction="vertical", simple theme, and custom icons.

<el-dropdown @command="handleCommand">
  <span class="el-dropdown-link">
    Actions<i class="el-icon-arrow-down el-icon--right"></i>
  </span>
  <el-dropdown-menu slot="dropdown">
    <el-dropdown-item command="edit">Edit</el-dropdown-item>
    <el-dropdown-item command="delete" divided>Delete</el-dropdown-item>
  </el-dropdown-menu>
</el-dropdown>
<el-page-header @back="goBack" content="Detail Page" title="Back">
</el-page-header>

Feedback Components

Dialog

<el-button @click="dialogVisible = true">Open Dialog</el-button>

<el-dialog title="Dialog Title" :visible.sync="dialogVisible" width="50%">
  <p>Dialog content here.</p>
  <span slot="footer">
    <el-button @click="dialogVisible = false">Cancel</el-button>
    <el-button type="primary" @click="dialogVisible = false">Confirm</el-button>
  </span>
</el-dialog>
Prop Type Default Description
visible boolean false Use with .sync modifier
title string — Dialog title
width string '50%' Dialog width
fullscreen boolean false Fullscreen mode
top string '15vh' Margin from top
modal boolean true Show overlay mask
close-on-click-modal boolean true Close on mask click
close-on-press-escape boolean true Close on Escape key
destroy-on-close boolean false Destroy inner content on close

Drawer

Side panel alternative to Dialog:

<el-drawer title="Settings" :visible.sync="drawerVisible" direction="rtl" size="30%">
  <p>Drawer content</p>
</el-drawer>

Direction options: rtl (right), ltr (left), ttb (top), btt (bottom).

Warning

When nesting Drawers or combining Drawers with Dialogs, set append-to-body on the inner component. Improper nesting without this prop can cause z-index layering issues (see issue #23137).

Tooltip

<el-tooltip content="Helpful tip" placement="top">
  <el-button>Hover me</el-button>
</el-tooltip>

Placement: top, top-start, top-end, bottom, left, right (and their -start/-end variants).

Popover

<el-popover placement="right" width="200" trigger="click" content="Popover content">
  <el-button slot="reference">Click me</el-button>
</el-popover>

Trigger modes: click, focus, hover, manual.

Popconfirm

<el-popconfirm title="Are you sure?" @confirm="handleConfirm">
  <el-button slot="reference">Delete</el-button>
</el-popconfirm>

Alert

<el-alert title="Info alert" type="info"></el-alert>
<el-alert title="Success" type="success" description="Operation completed" show-icon closable>
</el-alert>

Types: success, warning, info, error. Effects: light (default), dark.

Service Components

These components are invoked programmatically via this.$method() rather than as template tags.

Message

Global message displayed at the top of the page:

// Simple
this.$message('This is a message');

// Typed
this.$message.success('Success!');
this.$message.warning('Warning!');
this.$message.error('Error!');

// With options
this.$message({
  message: 'Congratulations!',
  type: 'success',
  duration: 5000,
  showClose: true,
  center: true,
  offset: 40
});

// Close all messages
this.$message.closeAll();
Option Type Default Description
message string/VNode — Message text
type string 'info' 'success', 'warning', 'info', 'error'
duration number 3000 Display time in ms (0 = persistent)
showClose boolean false Show close button
center boolean false Center text
offset number 20 Vertical offset from top in pixels
dangerouslyUseHTMLString boolean false Treat message as HTML
onClose function null Callback when closed

Notification

Corner notification with title and message:

this.$notify({
  title: 'Title',
  message: 'This is a notification',
  type: 'success',
  position: 'top-right',
  duration: 4500
});

// Shorthand
this.$notify.error({ title: 'Error', message: 'Something failed' });

// Close all
this.$notify.closeAll();
Option Type Default Description
title string — Notification title
message string/VNode — Notification body
type string — 'success', 'warning', 'info', 'error'
position string 'top-right' 'top-right', 'top-left', 'bottom-right', 'bottom-left'
duration number 4500 Display time in ms (0 = persistent)
showClose boolean true Show close button
offset number 0 Vertical offset in pixels
onClose function null Close callback
onClick function null Click callback

MessageBox

Modal dialog for confirmations and prompts:

// Alert
this.$alert('This is an alert', 'Title', { confirmButtonText: 'OK' });

// Confirm
this.$confirm('Are you sure?', 'Warning', {
  confirmButtonText: 'Yes',
  cancelButtonText: 'No',
  type: 'warning'
}).then(() => {
  this.$message.success('Confirmed');
}).catch(() => {
  this.$message.info('Cancelled');
});

// Prompt
this.$prompt('Enter your email', 'Prompt', {
  inputPattern: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/,
  inputErrorMessage: 'Invalid email format'
}).then(({ value }) => {
  this.$message.success('Email: ' + value);
});

Note

MessageBox returns a Promise. Use .then() for confirm and .catch() for cancel. Both $alert and $confirm use the same underlying $msgbox service.

Loading

Directive usage:

<div v-loading="isLoading">Content that's loading...</div>

<!-- Fullscreen -->
<div v-loading.fullscreen.lock="isLoading">Full page loading</div>

Customize via element attributes:

<div v-loading="true"
  element-loading-text="Loading..."
  element-loading-spinner="el-icon-loading"
  element-loading-background="rgba(0, 0, 0, 0.8)">
</div>

Service usage:

const loading = this.$loading({
  lock: true,
  text: 'Loading...',
  spinner: 'el-icon-loading',
  background: 'rgba(0, 0, 0, 0.7)',
  target: document.querySelector('.target-element')
});

// Close when done
loading.close();

Other Components

<el-carousel :interval="3000" height="200px">
  <el-carousel-item v-for="item in 4" :key="item">
    <div>Slide {{ item }}</div>
  </el-carousel-item>
</el-carousel>

Supports type="card" for card-style layout, direction="vertical", and arrow="always".

Collapse

<el-collapse v-model="activeNames">
  <el-collapse-item title="Section 1" name="1">Content 1</el-collapse-item>
  <el-collapse-item title="Section 2" name="2">Content 2</el-collapse-item>
</el-collapse>

<!-- Accordion mode -->
<el-collapse accordion v-model="activeName">
  <el-collapse-item title="Panel A" name="a">Only one open at a time</el-collapse-item>
  <el-collapse-item title="Panel B" name="b">Content B</el-collapse-item>
</el-collapse>

Timeline

<el-timeline>
  <el-timeline-item timestamp="2024-01-15" type="primary">Event 1</el-timeline-item>
  <el-timeline-item timestamp="2024-02-01" type="success">Event 2</el-timeline-item>
</el-timeline>

Image

<el-image src="/img/photo.jpg" fit="cover" lazy>
  <div slot="placeholder">Loading...</div>
  <div slot="error"><i class="el-icon-picture-outline"></i></div>
</el-image>

<!-- With preview -->
<el-image src="/img/photo.jpg" :preview-src-list="['/img/photo.jpg', '/img/photo2.jpg']">
</el-image>

Supports lazy loading (lazy), object-fit modes (fill, contain, cover, none, scale-down), and full-screen image preview.

Backtop

<el-backtop :visibility-height="200" :right="40" :bottom="40"></el-backtop>

InfiniteScroll

<ul v-infinite-scroll="loadMore" infinite-scroll-disabled="disabled"
  infinite-scroll-distance="10">
  <li v-for="item in list" :key="item.id">{{ item.name }}</li>
</ul>
Attribute Type Default Description
infinite-scroll-disabled boolean false Disable the scroll trigger
infinite-scroll-delay number 200 Throttle delay in ms
infinite-scroll-distance number 0 Distance threshold in px
infinite-scroll-immediate boolean true Execute immediately if content doesn't fill the container

Scrollbar

Custom scrollbar component (wraps content):

<el-scrollbar style="height: 300px;">
  <div>Long content...</div>
</el-scrollbar>

Card and Divider

<el-card shadow="hover">
  <div slot="header">Card Title</div>
  <p>Card content</p>
</el-card>

<el-divider></el-divider>
<el-divider content-position="center">Section Title</el-divider>
<el-divider direction="vertical"></el-divider>

5. Common Tasks

Build a complete CRUD form

Goal: Create a form with validation, submit to server, show success/error feedback.

Steps:

  1. Wrap fields in <el-form> with :model and :rules
  2. Each field in <el-form-item> with prop matching model key
  3. Validate on submit with this.$refs.form.validate()
  4. Show feedback with this.$message.success() or this.$message.error()
  5. Reset with this.$refs.form.resetFields()

Verify: All required fields show validation errors when empty. Success message appears after valid submit.

Build a data table with sorting, filtering, and pagination

Goal: Display server data with column sort, filter dropdowns, and page navigation.

Steps:

  1. Use <el-table> with :data bound to current page data
  2. Add sortable to columns that should be sortable
  3. Add filters and :filter-method to filterable columns
  4. Place <el-pagination> below the table
  5. Handle @current-change and @size-change events to fetch new data

Create a multi-level navigation sidebar

Goal: Vertical collapsible menu with router integration.

Steps:

  1. Use <el-menu> with router prop and :collapse bound to a toggle
  2. Add <el-menu-item> for leaf pages (set index to route path)
  3. Wrap grouped items in <el-submenu>
  4. Toggle collapse state with a button

Implement file upload with preview

Goal: Upload images with thumbnail preview and drag support.

Steps:

  1. Use <el-upload> with list-type="picture-card" and drag
  2. Set :action to your upload endpoint
  3. Use :before-upload to validate file type and size
  4. Handle :on-success to store server response
  5. Use :on-exceed to warn when file limit is reached

Build a date-ranged report filter

Goal: Let users pick a date range and filter a table.

Steps:

  1. Use <el-date-picker type="daterange"> with v-model
  2. Watch the model value and re-fetch data on change
  3. Use value-format="yyyy-MM-dd" for consistent string output

Customize the theme

Goal: Change primary color and component sizes globally.

Steps:

  1. Install element-theme: npm install element-theme element-theme-chalk -g
  2. Initialize: et -i (generates element-variables.scss)
  3. Edit $--color-primary and other variables
  4. Build: et
  5. Import the generated theme instead of the default CSS

Add internationalization

Goal: Support multiple languages in your app.

Steps:

  1. Import desired locale files from element-ui/lib/locale/lang/
  2. Use locale.use(lang) or integrate with vue-i18n
  3. Switch languages at runtime by calling locale.use() with a different pack

Create a dynamic form

Goal: Add/remove form items dynamically with validation.

Steps:

  1. Use a reactive array in your model (e.g., form.items: [])
  2. Loop with v-for, using index in the prop: prop="items." + index + ".value"
  3. Set rules on each dynamic <el-form-item>
  4. Add/remove items by pushing to or splicing the array

6. Troubleshooting

Error: Can not find table layout.

Cause: <el-table-column> used outside of <el-table>, or Table component not properly initialized.

Solution:

  1. Ensure every <el-table-column> is a direct child of <el-table>
  2. If columns are conditional, use v-if on the column, not on a wrapper div

Prevention: Always structure Table markup with columns as direct children.

Error: for nested data item, row-key is required.

Cause: Tree-structured table data provided without a row-key prop.

Solution:

<el-table :data="treeData" row-key="id">

Error: please transfer a valid prop path to form item!

Cause: The prop attribute on <el-form-item> doesn't match any key in the form model, or the model is undefined.

Solution:

  1. Verify :model is set on <el-form>
  2. Verify prop value matches a key path in the model object
  3. For nested paths, use : separator: prop="address:city"

Error: Invalid Date in fecha.format

Cause: DatePicker received an unparseable date value.

Solution:

  1. Ensure v-model is bound to a Date object, valid date string, or null
  2. If using value-format, ensure the format string matches your data

Error: className should not contain space.

Cause: Passing a class string with spaces to a utility function that expects a single class name.

Solution: When programmatically adding classes, pass one class at a time or use an array.

Table header misalignment with fixed columns

Cause: Known rendering issue in Chrome when tables have fixed columns and the content doesn't fill the viewport (issues #21619, #23134).

Solution:

  1. Call this.$refs.table.doLayout() after data changes or tab switches
  2. Use this.$nextTick() to ensure the DOM has updated before calling doLayout()

Table memory leak when navigating away

Cause: Element Table can hold DOM references after component destruction (issue #22980).

Solution:

  1. Ensure tables are properly destroyed when leaving routes
  2. Use v-if rather than v-show for conditional tables
  3. Clear table data before navigation: this.tableData = []

el-select soft keyboard not appearing on Android

Cause: Known issue with filterable/remote selects on Android devices where the native keyboard doesn't appear (issue #12563).

Solution:

  1. Use readonly attribute on the inner input and trigger a custom input
  2. Or use a native <select> on mobile as a fallback

Cascader placeholder overlap in multi+filterable mode

Cause: When both multiple and filterable are enabled, the placeholder text can overlap with selected tags (issue #23129).

Solution: Apply custom CSS to hide the placeholder when tags are present:

.el-cascader .el-input .el-input__inner::placeholder {
  opacity: 0;
}

Caution

Lodash v4.17.17 (bundled as a devDependency) has known security vulnerabilities. If your project uses Element UI's build system, consider upgrading lodash to 4.17.21 or later (issues #23127, #23132).

7. FAQ

Q: Does Element UI support Vue 3?

No. Element UI (this package) supports Vue 2.x only. For Vue 3, use Element Plus, the official successor.

Q: How do I import only specific components to reduce bundle size?

Use partial imports with babel-plugin-component. See the Installation section for setup details. Each component can be imported individually: import { Button, Table } from 'element-ui'.

Q: How do I change the default language from Chinese?

Import a language pack and set it before creating your Vue instance. See the Configuration section for examples with both direct locale setting and vue-i18n integration.

Q: Can I use Element UI with Nuxt.js?

Yes. Create a plugin file that imports Element UI, and register it in nuxt.config.js. Use ssr: false for the plugin since Element UI accesses browser APIs.

Q: How do I customize the theme colors?

Three approaches: (1) Override SCSS variables and rebuild with element-theme CLI, (2) Use the online theme editor at element.eleme.io, or (3) Override CSS custom properties at runtime. See Common Tasks for details.

Q: Why do my table columns misalign after a tab switch or data change?

Call this.$refs.table.doLayout() inside this.$nextTick() after the data changes or the table becomes visible again. This forces the table to recalculate column widths.

Q: How do I set a global component size?

Pass size in the options when calling Vue.use(ElementUI, { size: 'small' }). Valid sizes: 'medium', 'small', 'mini'.

Q: How do I access the Message/Notification service without this?

Import them directly:

import { Message, Notification } from 'element-ui';
Message.success('Done');
Notification({ title: 'Info', message: 'Hello' });

Q: How do I validate a form programmatically without user interaction?

Call this.$refs.formRef.validate() which returns a Promise (or accepts a callback). You can also validate individual fields with this.$refs.formRef.validateField('fieldName').

Q: Can I use Element UI components individually without Vue.use()?

Yes. Import each component and register it locally:

import { Button } from 'element-ui';
export default {
  components: { 'el-button': Button }
};