Conditional Visibility Attributes
Who has familiarity with Naughty Attributes or Odin Inspector will recognize the following attributes, which can be used to change the visibility of fields based on conditions expressed as arguments. They are compatible with both Odin Inspector and Naughty Attributes, but are meant to be used when those plugins have not been imported in a project.
These attributes do NOT support IMGUI and only work in UIElements Inspectors/Windows.
The general use of these attributes is the following:
[SerializeField, <Attribute>(<Conditions>)]
private int _affectedField;
Where <Attribute> can be one of ShowWhen, ShowWhenNot, HideWhen, HideWhenNot and <Conditions> is a list of mixed-types parameters with at least one string element (see below.)
ShowWhen(Not)
ShowWhen is used to show the affected field when the conditions are true, while ShowWhenNot does the same when the conditions are false.
[SerializeField]
private bool _condition;
[SerializeField, ShowWhen(nameof(_condition))]
private int _field1; // Visible if _condition == true
[SerializeFIeld, ShowWhenNot(nameof(_condition))]
private int _field2; // Visible if _condition == false
HideWhen(Not)
These attributes work as mirrors of ShowWhen/ShowWhenNot: HideWhen is used to hide the affected field when the conditions are true, while HideWhenNot does the same when the conditions are false.
[SerializeField]
private bool _condition;
[SerializeField, HideWhen(nameof(_condition))]
private int _field1; // Visible if _condition == false (hidden when true)
[SerializeFIeld, HideWhenNot(nameof(_condition))]
private int _field2; // Visible if _condition == true (hidden when false)
Unity applies custom property drawers in declaration order, which means the first attribute decleared onto a field wraps the following one, which in turn wraps the one after that, and so on. Some Unity attributes (e.g. Min, Max or Range, ColorUsage, GradientUsage, Multiline, TextArea) are terminal attributes, which means they interrupt this wrapping chain. To make sure a Conditional Visibility Attribute is always applied, make sure to declare it before those attributes.
[SerializeField, ShowWhen(nameof(_condition)), Min(0)] ✔️
[SerializeField, Min(0), ShowWhen(nameof(_condition))] ❌
Conditions
In their simplest form, Conditional Visibility Attributes require a single string parameter identifying a boolean field, property or method. But it can be a lot more powerful than that, allowing to specify different fields and the corresponding value to test equality against.
Valid types are byte, short, int, long, float, double, decimal, bool and char. object conditions are possible as long as they're used for a null-check, while Enum are generally valid regardless of the specific type.
enum EnumConditions { Condition1, Condition2, Condition3 }
[SerializeField]
private int _conditionField;
[SerializeField]
private EnumConditions _enumCondition;
[SerializeField]
private Transform _transform;
[SerializeField, ShowWhen(nameof(_conditionField), 5)]
private int _field1;
[SerializeField, ShowWhen(nameof(_enumCondition), EnumConditions.Condition1)]
private int _field2; // Visible if _enumCondition == EnumConditions.Condition1
[SerializeField, ShowWhen(nameof(_transform), null)]
private int _field3; // Visible if _transform == null
Condition fields don't have to be marked as Serialized Fields, even though their most common usecase is in response to other fields changing value from the inspector. In addition, both Properties and Methods names are valid parameters,
private int _conditionField;
public bool ConditionProperty { get; set; }
public bool ConditionMethod() => _conditionField == 5 && ConditionProperty;
[SerializeField, ShowWhen(nameof(_conditionField), 5)]
private int _field1;
[SerializeField, ShowWhen(nameof(ConditionProperty))]
private int _field2;
[SerializeField, ShowWhen(nameof(ConditionMethod))]
private int _field3;
Conditions can be combined with different logic operators:
[SerializeField]
private bool _bool;
[SerializeField]
private int _int;
[SerializeField, ShowWhen(nameof(_bool), nameof(_int), 5)]
private int _field1; // Visible if _bool == true AND _int == 5
[SerializeField, ShowWhen(LogicOperator.And, nameof(_bool), nameof(_int), 5)]
private int _field2; // Visible if _bool == true AND _int == 5, equivalent to the version above
[SerializeField, ShowWhen(LogicOperator.Or, nameof(_bool), nameof(_int), 5)]
private int _field3; // Visible if _bool == true OR _int == 5
[SerializeField, ShowWhen(LogicOperator.Xor, nameof(_bool), nameof(_int), 5)]
private int _field4; // Visible if _bool == true OR _int == 5 but not both
When using the negative version of these attributes (ShowWhenNot/HideWhenNot) the conditions are evaluated as normale, and only then the result gets negated. For instance, following the example above:
[SerializeField, ShowWhenNot(LogicOperator.Or, nameof(_bool), nameof(_int), 5)]
private int _field5; // Visible if NOT(_bool == true OR _int == 5) → _bool == false AND _int != 5