SuperAPI AI Directory

elementor-controls

General & other

View repository

Updated 10-16 03:17

About this skill

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 |

```php
// 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