Skip to main content

Rules

The Rules pattern allows users to build up a conditional logic statement in a visual way.

Anatomy of a rule

A complete rule is made up of blocks, which define specific conditions, and links, which allow additional blocks to be added.

── Rule container
└── rule block
└── rule block header
└── rule block controls
└── rule block control
└── rule links
└── rule link

For a rule which is structured in the IF/ELSE/AND/OR/RETURN format, the blocks and links are typically arranged within the following example heirarchy.

── IF block
| | └── OR link
| |── AND block
| | └── OR link
| |─── AND link
| └── RETURN block
|── ELSE IF link
└── ELSE RETURN block

Rule blocks

A rule block represents a single logical condition that must be matched for the rule to take this route. The controls within the rule block will be specific to the context of the parent user interface.

The rule classes define how the block is visually styled, the block must use the parent .rule-block class.

  • .rule-block--if
  • .rule-block--and
  • .rule-block--or
  • .rule-block--else
  • .rule-block--else-if
  • .rule-block--return
  • .rule-block--else-return
If rule condition

if

<div id="rule-form-container-1" class="rules-container rules-container--v2">
<fieldset class="rule-block rule-block--if">
<legend class="hide">If rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">if</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
<div class="rule-block__control">
{{
form.select({
'class': 'form__group--small',
'id': 'guid-' ~ random(),
'label': 'Choose logic',
'show-label': false,
'options': [
{
'label': 'is',
'value': 'value1'
},
{
'label': 'is not',
'value': 'value2'
}
]
})
}}
</div>
<div class="rule-block__control">
{{
form.select({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose value',
'show-label': false,
'placeholder': 'Choose value',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>
</div>

Removable blocks

Any blocks that a user has added by using the rule links should be removeable, this is achieved by adding the remove control as the last child of the rule block. These controls should also be present if a saved rule is loaded.

The first IF block, as well as all RETURN and ELSE RETURN blocks should not be removeable.

And rule condition

And

<div id="rule-form-container-2" class="rules-container rules-container--v2">
<fieldset class="rule-block rule-block--and">
<legend class="hide">And rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">And</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'placeholder': 'Choose condition',
'show-label': false,
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>
</div>

Indented blocks

When an OR block immediately follows an IF, AND or ELSE-IF rule, it should be indented using a rule-block--indent wrapper. Any rule links relating to this indented block should also be contained within the indent wrapper to maintain the layout of the ruleset.

If an OR block follows another OR block, it does not need to be further indented.

If rule condition

if

Or rule condition

or

Or rule condition

or

...
<div id="rule-form-container-3" class="rules-container rules-container--v2">
<fieldset class="rule-block rule-block--if">
<legend class="hide">If rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">if</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'placeholder': 'Choose condition',
'show-label': false,
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-block--indent">
<fieldset class="rule-block rule-block--or">
<legend class="hide">Or rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">or</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'placeholder': 'Choose condition',
'show-label': false,
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-trigger"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<fieldset class="rule-block rule-block--or">
<legend class="hide">Or rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">or</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'placeholder': 'Choose condition',
'show-label': false,
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--or">
<button class="btn" aria-label="Add a new OR condition">or</button>
</div>
</div>

</div><!-- /.ruleblock--indent -->

...

</div><!-- /.rules-container -->

Ruleset examples

Basic

This example demonstrates the starting point of an IF/ELSEIF/AND/OR/RETURN type ruleset.

If rule condition

if

Return

return

Else return

else return

<div id="rule-form-container-4" class="rules-container rules-container--v2">
<fieldset class="rule-block rule-block--if">
<legend class="hide">If rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">if</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--or">
<button class="btn" aria-label="Add a new OR condition">or</button>
</div>
<div class="rule-link rule-link--and">
<button class="btn" aria-label="Add a new AND condition">and</button>
</div>
</div>

<fieldset class="rule-block rule-block--return">
<legend class="hide">Return</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">return</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--else-if">
<button class="btn">else if</button>
</div>
</div>

<fieldset class="rule-block rule-block--else-return">
<legend class="hide">Else return</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">else return</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

</div><!-- /.rules-container -->

Full

This example shows a complex rule with various conditions visible, this is here for illustration purposes only.

If rule condition

if

Or rule condition

or

Or rule condition

or

And rule condition

and

Or rule condition

or

Return

return

Else If rule condition

else if

Return

return

Else return

else return

<div id="rule-form-container-5" class="rules-container rules-container--v2">
<fieldset class="rule-block rule-block--if">
<legend class="hide">If rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">if</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-block--indent">

<fieldset class="rule-block rule-block--or">
<legend class="hide">Or rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">or</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<fieldset class="rule-block rule-block--or">
<legend class="hide">Or rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">or</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--or">
<button class="btn" aria-label="Add a new OR condition">or</button>
</div>
</div>

</div><!-- /.ruleblock--indent -->

<fieldset class="rule-block rule-block--and">
<legend class="hide">And rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">and</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<div class="rule-block--indent">
<fieldset class="rule-block rule-block--or">
<legend class="hide">Or rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">or</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--or">
<button class="btn" aria-label="Add a new OR condition">or</button>
</div>
</div>
</div><!-- /.ruleblock--indent -->

<div class="rule-links">
<div class="rule-link rule-link--and">
<button class="btn" aria-label="Add a new AND condition">and</button>
</div>
</div>

<fieldset class="rule-block rule-block--return">
<legend class="hide">Return</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">return</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose return value',
'show-label': false,
'placeholder': 'Choose return value',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--else-if">
<button class="btn">else if</button>
</div>
</div>

<fieldset class="rule-block rule-block--else-if">
<legend class="hide">Else If rule condition</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">else if</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose condition',
'show-label': false,
'placeholder': 'Choose condition',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
<button data-action="remove" data-tippy-content="Remove this item" data-tippy-placement="left" class="btn remove-button js-remove-condition"><i class="icon-remove-sign"><span class="hide">Remove this item</span></i></button>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--or">
<button class="btn" aria-label="Add a new OR condition">or</button>
</div>
<div class="rule-link rule-link--and">
<button class="btn" aria-label="Add a new AND condition">and</button>
</div>
</div>

<fieldset class="rule-block rule-block--return">
<legend class="hide">Return</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">return</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose return value',
'show-label': false,
'placeholder': 'Choose return value',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

<div class="rule-links">
<div class="rule-link rule-link--else-if">
<button class="btn">else if</button>
</div>
</div>

<fieldset class="rule-block rule-block--else-return">
<legend class="hide">Else return</legend>
<div class="rule-block__header">
<h2 class="rule-block__heading">else return</h2>
</div>
<div class="rule-block__controls">
<div class="rule-block__control">
{{
form.select2({
'class': 'form__group--medium',
'id': 'guid-' ~ random(),
'label': 'Choose return value',
'show-label': false,
'placeholder': 'Choose return value',
'options': [
{
'label': 'Value one',
'value': 'value1'
},
{
'label': 'Value two',
'value': 'value2'
}
]
})
}}
</div>
</div>
</fieldset>

</div><!-- /.rules-container -->

Interactions

Currently, there is no associated JavaScript component to enable interactions for the rules user interface.