Overview#
The Modifiers module defines a system for defining how modifications can be consistently applied to elements on a page. In short the modules provides a way to alter the look and feel of entities on the page. Modifiers work by leveraging the power of the Drupal theming system - altering the render array of entities before they are rendered to the page.
– Modifier: Overview
Below is an example of a image parallex modifier provided by the “Modifiers Pack” module:

Below is an example of a confetti modifier written in custom module/theme applied to a paragraph component:

Install Modifier & Modifier Pack#
Step-1: Installation Of Preliminary Configuration
Install the Modifiers and Modifiers Pack module via composer and enable it via drush. Note that the Modifiers Pack module provides a lot more modifier options than what will be shown in the below example, you can check them via filtering with the “modifier” keyword in drupal module page at “/admin/modules” and enable them you require them: screenshot
1
2
3
4
| composer require 'drupal/modifiers:^1.6'
composer require 'drupal/modifiers_pack:^2.1'
drush pm:install modifiers
drush pm:install modifiers_color_background
|
Before starting to add modifiers, you will need to have a paragraph type to add modifers to and a content type to hold the corresponding paragraph entities. For demonstration purpose, I’ve created a paragraph type of only one formatted text field, and created a content type to hold it.
Step-2: Modifier Related Configurations
To add modifiers to a paragraph type, you will need to first create a “Paragraph” field of machine-name being exactly field_modifiers
to the paragraph type (or “Entity Reference Revisions” field of attribute “type of item to reference” set to “paragraph” but also need to have the exact machine-name of field_modifiers
, see screenshot):

Step-3: Create Content with Modifiers
We will then create a page with configured paragraph as its component, and add modifiers on the component we are creating and here’s the result:

Implementing Custom Modifiers#
The offcial guide on how to do this can be found on this page: https://www.drupal.org/docs/8/modules/modifiers/implementation. And you may also use the modifies included in the Modifier Pack module as examples for reference when writing your own module.
Modifier via Custom Module#
confetti_modifier / confetti_modifier.info.yml
1
2
3
4
5
6
7
8
| name: Confetti Modifier
type: module
description: Provides a custom modifier to turn anything into confetti button
core: 8.x
package: Modifiers
dependencies:
- modifiers:modifiers
- pargraphs:paragraphs
|
confetti_modifier / confetti_modifier.modifiers.yml
1
2
3
4
| js_confetti_modifier:
class: Drupal\confetti_modifier\Plugin\modifiers\JsConfettiModifier
label: 'ConfettiModifier'
description: 'Turns anything into a confetti button'
|
confetti_modifier / confetti_modifier.libraries.yml
(you can download the confetti.min.js
file form: https://confettijs.org/)
1
2
3
4
5
6
| modifiers_js_confetti_apply:
js:
js/modifiers_js_confetti.apply.js: {}
confetti:
js:
js/confetti/confetti.min.js: {}
|
confetti_modifier / src / Plugin / modifiers / JsConfettiModifier.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| <?php
namespace Drupal\confetti_modifier\Plugin\modifiers;
use Drupal\modifiers\Modification;
use Drupal\modifiers\ModifierPluginBase;
/**
* Provides a modifier to set the opacity of an element.
*
* @Modifier(
* id = "opacity_modifier",
* label = @Translation("Opacity Modifier"),
* description = @Translation("Provide a Modifier to set the colors on a element"),
*/
class JsConfettiModifier extends ModifierPluginBase {
public static function modification($selector, array $config) {
$css = [];
$attributes = [];
$media = parent::getMediaQuery($config);
$random_id = 'js-confetti-' . rand(1000, 9999);
// Add classname and random id to the element
$attributes[$media][$selector]['id'] = $random_id;
$attributes[$media][$selector]['class'][] = 'modifiers-js-confetti';
// Some style adujstment to make the element look like a button
$css[$media][$selector][] = 'padding:' . '1.0rem';
$css[$media][$selector][] = 'border-radius:' . '2.0rem';
$css[$media][$selector][] = 'background:' . '#FFC846';
$css[$media][$selector][] = 'transition:' . "all 0.2s ease-in-out";
$css[$media][$selector][] = 'border:' . '2px solid #FFC846';
$css[$media][$selector . ":hover"][] = 'border:' . '2px solid #00273E';
$css[$media][$selector . ":hover"][] = 'cursor:' . 'pointer';
// Add JS library and the associated callback function
$libraries = [
"confetti_modifier/confetti",
"confetti_modifier/modifiers_js_confetti_apply",
];
$settings = [
'namespace' => "JsConfettiModifier",
'callback' => 'apply',
'selector' => $selector,
'media' => $media,
'args' => []
];
// Adding argument for the associated callback function
$settings['args']['id'] = $random_id;
if(!empty($config['count'])){ $settings['args']['count'] = intval($config['count']); }
if(!empty($config['destoryobject_after_click'])){ $settings['args']['destroy'] = boolval($config['destoryobject_after_click']); }
if(!empty($config['fade'])){ $settings['args']['fade'] = boolval($config['fade']); }
if(!empty($config['power'])){ $settings['args']['power'] = intval($config['power']); }
if(!empty($config['size'])){ $settings['args']['size'] = floatval($config['size']); }
// Return the result css and attributes
if (!empty($css) || !empty($attributes)) {
return new Modification(
$css,
$libraries,
$settings,
$attributes);
}
// Handle Edge-Condition Where No Modification Made
return NULL;
}
}
|
confetti_modifier / js / modifiers_js_confetti.apply.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| /**
* @file
* Initializes modification based on provided configuration.
*/
(function (JsConfettiModifier) {
'use strict';
JsConfettiModifier.apply = function (context, selector, media, config) {
// Get the element
var element = context.querySelector(selector);
if (!element){return;}
// Initialize the confetti object
var confetti = new Confetti(config.id);
confetti.setCount(config.count);
confetti.destroyTarget(config.destroy);
confetti.setFade(config.fade);
confetti.setPower(config.power);
confetti.setSize(config.size);
};
})(window.JsConfettiModifier = window.JsConfettiModifier || {});
|
confetti_modifier / config / install
(configuration files in this folder are used to create the modifier paragraph type on installation of the module, you can refer to the this guide on how to export these configurations:
https://www.drupal.org/docs/contributed-modules/configuration-kits/create-your-own-configuration-kit)
1
2
3
4
5
6
7
8
9
| core.entity_form_display.paragraph.js_confetti_modifier.default.yml
core.entity_view_display.paragraph.js_confetti_modifier.default.yml
field.field.paragraph.content.field_modifiers.yml
field.field.paragraph.js_confetti_modifier.field_count.yml
field.field.paragraph.js_confetti_modifier.field_destoryobject_after_click.yml
field.field.paragraph.js_confetti_modifier.field_fade.yml
field.field.paragraph.js_confetti_modifier.field_power.yml
field.field.paragraph.js_confetti_modifier.field_size.yml
paragraphs.paragraphs_type.js_confetti_modifier.yml
|
Modifier via Sub Theme#
(Pretty much the same as the custom module, except for you are using the theme name as the namespace instead, and you will create the paragraph types and the fields yourself)
bootstrap_custom_theme / bootstrap_custom_theme.modifiers.yml
1
2
3
4
| js_confetti_modifier:
class: Drupal\sia\Plugin\modifiers\JsConfettiModifier
label: 'ConfettiModifier'
description: 'Turns anything into a confetti button'
|
bootstrap_custom_theme / bootstrap_custom_theme.libraries.yml
1
2
3
4
5
6
| modifiers_js_confetti_apply:
js:
js/modifiers_js_confetti.apply.js: {}
confetti:
js:
js/confetti/confetti.min.js: {}
|
bootstrap_custom_theme / src / Plugin / modifiers / JsConfettiModifier.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| <?php
namespace Drupal\sia\Plugin\modifiers;
use Drupal\modifiers\Modification;
use Drupal\modifiers\ModifierPluginBase;
/**
* Provides a modifier to set the opacity of an element.
*
* @Modifier(
* id = "opacity_modifier",
* label = @Translation("Opacity Modifier"),
* description = @Translation("Provide a Modifier to set the colors on a element"),
*/
class JsConfettiModifier extends ModifierPluginBase {
public static function modification($selector, array $config) {
$css = [];
$attributes = [];
$media = parent::getMediaQuery($config);
$random_id = 'js-confetti-' . rand(1000, 9999);
// Add classname and random id to the element
$attributes[$media][$selector]['id'] = $random_id;
$attributes[$media][$selector]['class'][] = 'modifiers-js-confetti';
// Some style adujstment to make the element look like a button
$css[$media][$selector][] = 'padding:' . '1.0rem';
$css[$media][$selector][] = 'border-radius:' . '2.0rem';
$css[$media][$selector][] = 'background:' . '#FFC846';
$css[$media][$selector][] = 'transition:' . "all 0.2s ease-in-out";
$css[$media][$selector][] = 'border:' . '2px solid #FFC846';
$css[$media][$selector . ":hover"][] = 'border:' . '2px solid #00273E';
$css[$media][$selector . ":hover"][] = 'cursor:' . 'pointer';
// Add JS library and the associated callback function
$libraries = [
"sia/confetti",
"sia/modifiers_js_confetti_apply",
];
$settings = [
'namespace' => "JsConfettiModifier",
'callback' => 'apply',
'selector' => $selector,
'media' => $media,
'args' => []
];
// Adding argument for the associated callback function
$settings['args']['id'] = $random_id;
if(!empty($config['count'])){ $settings['args']['count'] = intval($config['count']); }
if(!empty($config['destoryobject_after_click'])){ $settings['args']['destroy'] = boolval($config['destoryobject_after_click']); }
if(!empty($config['fade'])){ $settings['args']['fade'] = boolval($config['fade']); }
if(!empty($config['power'])){ $settings['args']['power'] = intval($config['power']); }
if(!empty($config['size'])){ $settings['args']['size'] = floatval($config['size']); }
// Return the result css and attributes
if (!empty($css) || !empty($attributes)) {
return new Modification(
$css,
$libraries,
$settings,
$attributes);
}
// Handle Edge-Condition Where No Modification Made
return NULL;
}
}
|
bootstrap_custom_theme / js / modifiers_js_confetti.apply.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| /**
* @file
* Initializes modification based on provided configuration.
*/
(function (JsConfettiModifier) {
'use strict';
JsConfettiModifier.apply = function (context, selector, media, config) {
// Get the element
var element = context.querySelector(selector);
if (!element){return;}
// Initialize the confetti object
var confetti = new Confetti(config.id);
confetti.setCount(config.count);
confetti.destroyTarget(config.destroy);
confetti.setFade(config.fade);
confetti.setPower(config.power);
confetti.setSize(config.size);
};
})(window.JsConfettiModifier = window.JsConfettiModifier || {});
|
Final Outcome#

Reference#
Modifier Officla Documentation
- Overview: outlining the purpose and the key concepts of the module
- Quick Start: example usage of the modifier module via paragraph
- Implementation: how to implement modifier into custom module or theme
Helpful Modules Recommended
- Modfier Pack: where you can find a handful of practical example of modifier to help you write your modifier in custom module
- Look: Manages collections of Modifiers and assigns them to selectors on a page. Helpful for when you want to modify theme regions and other elements which are not represented by an entity.
- Modifiers Vanta: This module is an addition to set of Modifiers which provides animated backgrounds for your components. It is using Vanta.js 3rd party library which allows you to set nice animated backgrounds. See examples at Vanta.js.
Alternative to Modifier Modules
- Entity Class Formatter:
- Allow editors to select a class to drop onto an entity, allowing the entity to be themed. This is a much simpler approach than Modifiers because editors only need to select a single option, rather than creating a Modifier.
- Useful when you don’t want to create reusable modifications across the system for all entities, but just want to give alterations to a specific entity (e.g. content, paragraph)
- Demo vidoe by NonProfit can be found at: https://vimeo.com/290512765