Elementor Controls Reference
- Controls Overview
Controls are the fields in the Elementor editor panel that allow users to configure widgets. Every control must live inside a section.
Basic pattern:
$this->start_controls_section('section_id', [ 'label' => esc_html__('Section', 'textdomain'), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, // or TAB_STYLE ]);
$this->add_control('control_id', [ 'label' => esc_html__('Label', 'textdomain'), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', ]);
$this->end_controls_section();
Control base classes:
Base Class Purpose Examples
Base_Data_Control
Controls that store a single value TEXT, SELECT, COLOR, SWITCHER, NUMBER
Control_Base_Multiple
Controls returning arrays URL, MEDIA, ICONS, IMAGE_DIMENSIONS
Control_Base_Units
Controls with size + unit SLIDER, DIMENSIONS
Base_UI_Control
Display-only, no stored data HEADING, DIVIDER, ALERT, RAW_HTML
Group_Control_Base
Grouped sets of controls Typography, Background, Border
Available tabs: TAB_CONTENT , TAB_STYLE , TAB_ADVANCED , TAB_RESPONSIVE , TAB_LAYOUT
Common parameters (all controls): label , description , show_label (bool), label_block (bool), separator (default |before |after ), condition , conditions , classes , dynamic , global , frontend_available
- Data Controls Quick Reference
Full PHP code examples for all data controls: see resources/data-controls-examples.md
Text Input Controls
Control Constant Returns Key Params
Text TEXT
string
input_type , placeholder , title
Textarea TEXTAREA
string
rows , placeholder
WYSIWYG WYSIWYG
string
(rich text editor)
Code CODE
string
language (html |css |javascript ), rows
Number NUMBER
string
min , max , step , placeholder
Hidden HIDDEN
string
default (only param that matters)
Selection Controls
Control Constant Returns Key Params
Select SELECT
string
options (key=>label array), groups
Select2 SELECT2
string|array
options , multiple (bool), select2options
Choose CHOOSE
string
options (key=>[title,icon]), toggle (bool)
Visual Choice VISUAL_CHOICE
string
options (key=>[title,image])
Switcher SWITCHER
string
label_on , label_off , return_value (default 'yes' )
Unit / Dimension Controls
Control Constant Returns Key Params
Slider SLIDER
['size'=>int, 'unit'=>string]
size_units , range (per unit: min/max/step)
Dimensions DIMENSIONS
['top','right','bottom','left','unit','isLinked']
size_units , range , allowed_dimensions
Image Dimensions IMAGE_DIMENSIONS
['width'=>int, 'height'=>int]
default
Media / Asset Controls
Control Constant Returns Key Params
Color COLOR
string (hex/rgba) alpha (bool, default true)
Media MEDIA
['id'=>int, 'url'=>string]
media_types (default ['image'] )
Gallery GALLERY
array of ['id','url']
default
Icons ICONS
['value'=>string, 'library'=>string]
default , fa4compatibility , recommended , skin
Icon ICON
string
DEPRECATED - use ICONS instead
Font FONT
string
default
URL URL
['url','is_external','nofollow','custom_attributes']
placeholder , autocomplete , options
Date Time DATE_TIME
string
picker_options (Flatpickr config)
REPEATER
Returns: array of rows, each row is an assoc array of field values. Use title_field for dynamic row labels.
Render: PHP: $settings['list'] is array of rows. Each row has _id key. Use class elementor-repeater-item-{$item['_id']} for per-item styling with {{CURRENT_ITEM}} . JS template: _.each(settings.list, function(item) { ... item._id ... })
POPOVER_TOGGLE
Used with start_popover() / end_popover() to group controls in a popup.
- UI Controls
UI controls display information in the panel but store no data.
Control Constant Key Params Purpose
Heading HEADING
label
Section heading text
Divider DIVIDER
Horizontal separator line
Alert ALERT
alert_type (info |success |warning |danger ), content
Colored alert box
Notice NOTICE
notice_type , content , dismissible (bool), heading
Dismissible notice
Raw HTML RAW_HTML
raw , content_classes
Arbitrary HTML in panel
Button BUTTON
text , button_type (default |success ), event
Clickable button
Deprecated Notice DEPRECATED_NOTICE
widget , since , last , plugin , replacement
Deprecation warning
// HEADING $this->add_control('heading_style', [ 'label' => esc_html__('Title Style', 'textdomain'), 'type' => \Elementor\Controls_Manager::HEADING, 'separator' => 'before', ]);
// DIVIDER $this->add_control('hr', [ 'type' => \Elementor\Controls_Manager::DIVIDER, ]);
- Group Controls
Group controls bundle multiple related controls. Use add_group_control() with selector (singular, string) for CSS targeting.
Full PHP code examples for group controls, fields_options, custom controls, and global styles: see resources/group-custom-controls.md
Group Control Class Type Getter Key Params
Typography Group_Control_Typography
::get_type()
selector , fields_options , global
Background Group_Control_Background
::get_type()
selector , types (classic |gradient |video |slideshow )
Border Group_Control_Border
::get_type()
selector , fields_options
Box Shadow Group_Control_Box_Shadow
::get_type()
selector , exclude
Text Shadow Group_Control_Text_Shadow
::get_type()
selector , exclude
Text Stroke Group_Control_Text_Stroke
::get_type()
selector , exclude
CSS Filter Group_Control_Css_Filter
::get_type()
selector , exclude
Image Size Group_Control_Image_Size
::get_type()
include , exclude , default
Common group control params: name (required, unique prefix), selector , exclude (array of inner control names), fields_options (override inner control settings).
- Structural Controls
Sections
Every control must be inside a section. Sections appear as collapsible panels.
$this->start_controls_section('section_id', [ 'label' => esc_html__('Section Name', 'textdomain'), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, // default 'condition' => [], // optional ]); // ... controls ... $this->end_controls_section();
Tabs (within a section)
Group controls into switchable tabs (e.g., Normal / Hover).
$this->start_controls_tabs('style_tabs');
$this->start_controls_tab('normal_tab', [ 'label' => esc_html__('Normal', 'textdomain'), ]); // ... normal state controls ... $this->end_controls_tab();
$this->start_controls_tab('hover_tab', [ 'label' => esc_html__('Hover', 'textdomain'), ]); // ... hover state controls ... $this->end_controls_tab();
$this->end_controls_tabs();
Popovers
Group controls in a popup that appears on toggle.
$this->add_control('popover_toggle', [ 'type' => \Elementor\Controls_Manager::POPOVER_TOGGLE, 'label' => esc_html__('Options', 'textdomain'), 'label_off' => esc_html__('Default', 'textdomain'), 'label_on' => esc_html__('Custom', 'textdomain'), 'return_value' => 'yes', ]); $this->start_popover(); // ... controls ... $this->end_popover();
- CSS Selectors
The {{WRAPPER}} Pattern
All selectors should use {{WRAPPER}} for scoped styling. Resolves to .elementor-{page_id} .elementor-element.elementor-element-{widget_id} .
Value Placeholders by Control Type
Control Type Selector Pattern
String controls (TEXT, SELECT, COLOR, etc.) '{{WRAPPER}} .el' => 'property: {{VALUE}};'
SLIDER '{{WRAPPER}} .el' => 'width: {{SIZE}}{{UNIT}};'
DIMENSIONS '{{WRAPPER}} .el' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
URL / MEDIA '{{WRAPPER}} .el' => 'background-image: url({{URL}});'
Multiple Properties in One Selector
'selectors' => [ '{{WRAPPER}} .el' => 'color: {{VALUE}}; border-color: {{VALUE}}; outline-color: {{VALUE}};', ],
Multiple / Comma-Separated Selectors
'selectors' => [ '{{WRAPPER}} .heading, {{WRAPPER}} .content' => 'color: {{VALUE}};', ], // OR as separate keys: 'selectors' => [ '{{WRAPPER}} .heading' => 'color: {{VALUE}};', '{{WRAPPER}} .content' => 'color: {{VALUE}};', ],
RTL/LTR Support
'selectors' => [ 'body:not(.rtl) {{WRAPPER}} .el' => 'padding-left: {{VALUE}};', 'body.rtl {{WRAPPER}} .el' => 'padding-right: {{VALUE}};', ],
Hover States
// Via group control: 'selector' => '{{WRAPPER}}:hover .el', // Via tabs: put controls in a "Hover" tab
Cross-Control Values
Reference another control's value by prefixing with the control name:
$this->add_control('aspect_width', [ 'type' => \Elementor\Controls_Manager::NUMBER, ]); $this->add_control('aspect_height', [ 'type' => \Elementor\Controls_Manager::NUMBER, 'selectors' => [ '{{WRAPPER}} img' => 'aspect-ratio: {{aspect_width.VALUE}} / {{aspect_height.VALUE}};', ], ]);
Selectors Dictionary
Transform old stored values to new CSS values (backward compat). Only works with string-returning controls.
$this->add_control('align', [ 'type' => \Elementor\Controls_Manager::CHOOSE, 'selectors_dictionary' => [ 'left' => is_rtl() ? 'end' : 'start', 'right' => is_rtl() ? 'start' : 'end', ], 'selectors' => [ '{{WRAPPER}} .el' => 'text-align: {{VALUE}};', ], ]);
Element ID
{{ID}} resolves to the element's unique ID. Discouraged -- prefer {{WRAPPER}} .
- Responsive Controls
Use add_responsive_control() instead of add_control() . Automatically creates per-device controls.
$this->add_responsive_control('spacing', [ 'label' => esc_html__('Spacing', 'textdomain'), 'type' => \Elementor\Controls_Manager::SLIDER, 'range' => ['px' => ['min' => 0, 'max' => 100]], 'devices' => ['desktop', 'tablet', 'mobile'], // optional, default all 3 'default' => ['size' => 30, 'unit' => 'px'], 'tablet_default' => ['size' => 20, 'unit' => 'px'], 'mobile_default' => ['size' => 10, 'unit' => 'px'], 'selectors' => [ '{{WRAPPER}} .el' => 'margin-bottom: {{SIZE}}{{UNIT}};', ], ]);
The devices parameter limits which breakpoints appear. Per-device defaults use tablet_default and mobile_default keys. Group controls automatically support responsive for their inner controls.
- Conditional Display
Basic condition Parameter
// Show only when 'border' switcher is 'yes' 'condition' => ['border' => 'yes'],
// Show when value is one of multiple options (OR) 'condition' => ['type' => ['option1', 'option2']],
// Multiple conditions (AND) 'condition' => [ 'border' => 'yes', 'border_style!' => '', // ! suffix = not equal ],
Advanced conditions Parameter
Supports operators: == , != , !== , === , in , !in , contains , !contains , < , <= , > , >=
'conditions' => [ 'relation' => 'or', // 'and' (default) or 'or' 'terms' => [ ['name' => 'type', 'operator' => '===', 'value' => 'video'], ['name' => 'type', 'operator' => '===', 'value' => 'slideshow'], ], ],
Conditions can be nested. Repeater inner fields can only depend on other inner fields, NOT outer controls.
- Dynamic Content
Enable dynamic tags (Elementor Pro) on any data control:
$this->add_control('heading', [ 'label' => esc_html__('Heading', 'textdomain'), 'type' => \Elementor\Controls_Manager::TEXT, 'dynamic' => ['active' => true], ]);
Works with: TEXT, TEXTAREA, NUMBER, URL, MEDIA, WYSIWYG, and most data controls.
Frontend Available
$this->add_control('slides_count', [ 'type' => \Elementor\Controls_Manager::NUMBER, 'default' => 3, 'frontend_available' => true, // default: false ]);
Access in JS handler: this.getElementSettings('slides_count')
- Global Styles
Use the global parameter to inherit from the site's design system (set in Site Settings).
Global Colors Constants
-
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY
-
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_SECONDARY
-
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT
-
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_ACCENT
Global Typography Constants
-
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY
-
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_SECONDARY
-
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT
-
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_ACCENT
Controls with global show a globe icon for users to pick a global style or set custom.
- Common Mistakes
Mistake Correct Approach
Using add_control() outside a section Always wrap in start_controls_section() / end_controls_section()
Using selector (singular) on non-group controls Non-group controls use selectors (plural, array). Group controls use selector (singular, string).
Forgetting {{WRAPPER}} in selectors Always prefix selectors with {{WRAPPER}} for scoped styles
Using {{VALUE}} with SLIDER control SLIDER returns array; use {{SIZE}}{{UNIT}}
Using {{VALUE}} with DIMENSIONS control Use {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}
Using {{VALUE}} with URL/MEDIA control Use {{URL}} for the URL component
Nesting start_controls_section inside another Sections cannot be nested. End one before starting another.
Putting tabs outside a section start_controls_tabs() must be inside a section
Repeater inner field depending on outer control Conditional display across repeater levels is not supported
Using selectors_dictionary with array-returning controls Only works with string-value controls (TEXT, SELECT, CHOOSE, etc.)
Not using esc_html__() for labels Always internationalize user-facing strings
Setting SWITCHER default to true or 1
SWITCHER returns a string; default should be 'yes' or ''
Using innerHTML = on frontend Use Elementor's rendering patterns; may be blocked by CSP
Setting REPEATER prevent_empty wrong Defaults to true ; set false if all rows should be deletable