# Custom Attributes

A rich set of inspector attributes for creating clean, organized, and interactive Unity inspector UIs. Available on any `MonoBehaviour`, `ScriptableObject`, or serializable class via the `BeeLabs.Attributes` namespace.

***

## Conditional Visibility

### ShowIf / HideIf

Show or hide fields based on other field values. Supports boolean member checks and value matching (including enums).

```csharp
[SerializeField] private bool useCustomSettings;

[ShowIf("useCustomSettings")]
[SerializeField] private float customValue;      // shown when useCustomSettings == true

[HideIf("useCustomSettings")]
[SerializeField] private float defaultValue;     // hidden when useCustomSettings == true

// With enum comparison
[SerializeField] private Mode mode;

[ShowIf("mode", Mode.Advanced)]
[SerializeField] private AdvancedSettings settings;
```

**Evaluation rules:**

* Single-argument form (`[ShowIf("_boolField")]`) — shows the field when the referenced boolean is `true`.
* Two-argument form (`[ShowIf("_field", SomeValue)]`) — shows the field when the referenced member equals `SomeValue`. Enum comparisons use integer conversion.
* Works correctly inside `FoldoutGroup` — visibility is evaluated at draw time, not at collection time.

### EnableIf / DisableIf

Enable or disable (gray out) fields based on conditions. The field remains visible but non-editable when disabled.

```csharp
[SerializeField] private bool isEditable;

[EnableIf("isEditable")]
[SerializeField] private string editableText;

[DisableIf("isEditable")]
[SerializeField] private string readOnlyWhenEditable;
```

***

## Grouping

### Foldout / FoldoutGroup

Group fields into collapsible sections. `ShowIf` and `HideIf` on the **first property** of a group will hide the entire foldout when the condition is not met.

```csharp
[Foldout("Movement Settings", true)] // true = expanded by default
[SerializeField] private float speed;

[Foldout("Movement Settings")]
[SerializeField] private float acceleration;

// Hiding an entire foldout with ShowIf on the first property:
[SerializeField] private bool _useAdvanced;

[Foldout("Advanced", true), ShowIf("_useAdvanced")]
[SerializeField] private float _advancedSetting1;  // foldout hidden when _useAdvanced is false

[Foldout("Advanced")]
[SerializeField] private float _advancedSetting2;
```

### BoxGroup

Group fields in a labeled visual box.

```csharp
[BoxGroup("Player Stats")]
[SerializeField] private int health;

[BoxGroup("Player Stats")]
[SerializeField] private int mana;
```

***

## Validation

### Required

Mark fields as required — shows a warning if the field is null or empty.

```csharp
[Required]
[SerializeField] private Transform target;

[Required("Audio clip must be assigned!")]
[SerializeField] private AudioClip sound;
```

* `ErrorText` — Custom error message (optional). Defaults to `"[FieldName] is required"` when null.

### MinValue / MaxValue

Constrain numeric values.

```csharp
[MinValue(0)]
[SerializeField] private float speed;

[MinValue(0), MaxValue(1)]
[SerializeField] private float normalizedValue;
```

### ValidateInput

Validate a field value using a named method.

```csharp
[ValidateInput("IsPositive", "Value must be positive.")]
[SerializeField] private float damage;

private bool IsPositive(float value) => value > 0f;
```

* `ValidationMethod` — Name of the method to invoke
* `ErrorText` — Message shown when validation fails

***

## Display

### Label

Override the displayed field name.

```csharp
[Label("Movement Speed (m/s)")]
[SerializeField] private float speed;
```

### ReadOnly

Display a field that cannot be edited.

```csharp
[ReadOnly]
[SerializeField] private string generatedId;
```

### ProgressBar

Display a value as a progress bar.

```csharp
[ProgressBar("Health", 100f)]
[SerializeField] private float health;

// Ceiling from another field
[ProgressBar("Health", "maxHealth")]
[SerializeField] private float currentHealth;

// With custom tint
[ProgressBar("Mana", 50f, InspectorPalette.Sapphire)]
[SerializeField] private float mana;
```

### MinMaxSlider

Display a `Vector2` as a dual-handle range slider.

```csharp
[MinMaxSlider(0f, 100f)]
[SerializeField] private Vector2 damageRange;

float damage = Random.Range(damageRange.x, damageRange.y);
```

### InfoBox

Display a notice box with optional severity styling.

```csharp
[InfoBox("This setting affects performance.")]
[SerializeField] private int particleCount;

[InfoBox("Caution: High values may cause lag!", NoticeSeverity.Caution)]
[SerializeField] private float updateRate;

[InfoBox("Critical: Do not change in production!", NoticeSeverity.Critical)]
[SerializeField] private bool debugMode;
```

**Severity values:** `NoticeSeverity.Info`, `NoticeSeverity.Caution`, `NoticeSeverity.Critical`.

### Dropdown

Present a dropdown picker populated from a field, property, or method.

```csharp
[Dropdown("GetWeaponNames")]
[SerializeField] private string selectedWeapon;

private List<string> GetWeaponNames()
    => new List<string> { "Sword", "Bow", "Staff", "Dagger" };
```

### EnumFlags

Renders a `[System.Flags]` enum as a multi-select bitmask control.

```csharp
[System.Flags]
public enum EnemyCapability { None = 0, Patrol = 1, Chase = 2, Shoot = 4 }

[EnumFlags]
[SerializeField] private EnemyCapability capabilities;
```

### HorizontalLine

Draws a coloured separator rule above the next field.

```csharp
[HorizontalLine]
[SerializeField] private float speed;

[HorizontalLine(3f, InspectorPalette.Sapphire)]
[SerializeField] private float health;
```

### ResizableTextArea

Auto-expanding multi-line text area.

```csharp
[ResizableTextArea]
[SerializeField] private string description;
```

### ShowAssetPreview

Displays a thumbnail image below an asset reference field.

```csharp
[ShowAssetPreview]
[SerializeField] private Sprite icon;

[ShowAssetPreview(128, 128)]
[SerializeField] private Texture2D portrait;
```

### CurveRange

Constrains an `AnimationCurve` to a fixed rectangular edit region.

```csharp
[CurveRange(0f, 0f, 1f, 1f)]
[SerializeField] private AnimationCurve fadeCurve;

[CurveRange(0f, 0f, 2f, 1f, InspectorPalette.Sapphire)]
[SerializeField] private AnimationCurve speedCurve;
```

***

## Selectors

### Tag / Layer

```csharp
[Tag]
[SerializeField] private string targetTag;

[Layer]
[SerializeField] private int collisionLayer;
```

### Scene

```csharp
[Scene]
[SerializeField] private string sceneName;
```

### AnimatorParam

```csharp
[AnimatorParam("animator")]
[SerializeField] private string parameterName;

[SerializeField] private Animator animator;
```

### SortingLayer / InputAxis

```csharp
[SortingLayer]
[SerializeField] private string sortingLayer;

[InputAxis]
[SerializeField] private string moveAxis;
```

***

## Interactivity

### Button

Renders a method as a clickable button at the bottom of the inspector.

```csharp
[Button]
private void ResetState() { }

[Button("Reload Config")]
private void ReloadConfiguration() { }

[Button(ButtonMode.PlayModeOnly)]
private void SpawnEnemy() { }

[Button("Bake Navmesh", ButtonMode.EditModeOnly)]
private void BakeNavigation() { }
```

**`ButtonMode` values:** `Anytime` (default), `EditModeOnly`, `PlayModeOnly`.

> Methods returning `IEnumerator` are automatically treated as coroutines and are only invokable during Play Mode.

### OnValueChanged

Calls a named void method whenever the field's value changes in the inspector.

```csharp
[OnValueChanged("OnSpeedChanged")]
[SerializeField] private float speed;

private void OnSpeedChanged()
{
    Debug.Log($"Speed changed to {speed}");
}
```

* `CallbackName` — Name of the parameterless void method to invoke on change


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://beelabs-dev.gitbook.io/beelabs-docs/beelabs-tools/custom-attributes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
