Skip to content

Show the required indicator (*) reactively for required_if and other conditional required_* rules #1462

@joshdaugherty

Description

@joshdaugherty

When a blueprint field has validate: required, Statamic shows a red * next to the field label in the Control Panel, telling the user up front which fields they must fill in.

However, when a field uses a conditional required rule — required_if, required_if_accepted, required_if_declined, required_unless, required_with, required_with_all, required_without, required_without_all — no indicator is ever shown, even when the condition is currently satisfied and the field is in fact required for a successful save.

The result is that users see a field with no required marker, try to submit, and get a validation error they had no way to anticipate. The conditional-required rules are powerful, but the UI gives the editor no feedback that they've just made a sibling field required.

Proposal

When a field's validate rules include any required_* rule, evaluate the condition reactively against the current form values and show the required indicator whenever the condition is satisfied. The indicator should appear/disappear in real time as the editor changes the dependent fields — the same way conditional-field visibility (if/unless/show_when/hide_when) already updates reactively.

Concretely, this may mean:

  1. Stop stripping validate before it reaches the front-end. src/Fields/Field.php:282 currently does unset($array['validate']) inside toPublishArray(). The Vue layer needs the raw rule list to evaluate conditions client-side.
  2. Make isRequired a reactive computed in the Publish field component. resources/js/components/ui/Publish/Field.vue:85 currently reads props.config.required as a static prop. It should instead compute over (a) the static required flag and (b) any required_* rules evaluated against the live container values.
  3. Add a client-side evaluator for the required_ family*, parallel to the existing ShowField evaluator used for conditional visibility (Field.vue:140-150). The infrastructure for reading sibling values reactively already exists — this is the same mechanism, applied to a different output.
  4. Server-side isRequired() can stay as-is for the rules-collection use cases internal to the framework; the reactive change is purely a UI affordance. Or, optionally, accept a context parameter so it can evaluate conditional rules against a known data set when needed.

Alternatives Considered

  • Treat any required_ rule as "always required" in the UI. Easy server-side patch, but it's worse than the current behavior — it lies to the editor by showing * even when the condition isn't met.
  • Custom fieldtype wrapper / service-provider override. Workable for the static-asterisk case (option above) but cannot deliver the reactive behavior, because the Vue components and toPublishArray()'s unset('validate') aren't reachable from user code without forking core.
  • Render the asterisk in field instructions / a custom label. Hacky, doesn't compose, and addons / blueprint authors shouldn't have to reimplement a core affordance.

Additional context

The rules that should be considered conditional-required: required_if, required_if_accepted, required_if_declined, required_unless, required_with, required_with_all, required_without, required_without_all. Laravel's Illuminate\Validation\Concerns\ValidatesAttributes is the source of truth for their semantics — the client-side evaluator should mirror those.

This pairs naturally with the existing conditional-visibility system: a field that's only shown when X has a value is often also required only when X has a value, and right now editors get the visibility cue but no requiredness cue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions