elementor-controls

SKILL.md

Elementor Controls Reference

1. 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

2. 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.

3. 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,
]);

4. 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).

5. 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();

6. 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}}.

7. 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.

8. 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.

9. 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')

10. 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.

12. 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
Weekly Installs
15
GitHub Stars
3
First Seen
Feb 4, 2026
Installed on
opencode15
gemini-cli11
claude-code11
codex11
github-copilot9
amp8