`.
+`containerProps()` targets the dropdown's `` or the group's `
`.
For native group-wide disabling, use
-`->checkbox()->wrapperProps('disabled disabled')` (or `radio()`); the browser
+`->checkbox()->containerProps('disabled disabled')` (or `radio()`); the browser
disables descendants through fieldset semantics, without rewriting the inputs.
Disabling a dropdown instead requires `inputProps('disabled disabled')`.
`labelProps()` targets the dropdown's label or the group's legend.
@@ -175,6 +175,14 @@ argument and explicit mode methods instead. A warning forces
warning, caller-supplied guidance and invalid-state properties remain unchanged.
Other repeated properties use the element builder's normal last-value behavior.
+### Migrating from wrapperProps
+
+In 5.0, use `containerProps()` instead of `wrapperProps()` on all form
+components. This is a rename, not a change in property handling or target
+elements. `wrapperProps()` remains a forwarding alias throughout 5.x and is
+marked with PHP's native `#[Deprecated]` attribute (supported since PHP 8.4).
+Calling it emits `E_USER_DEPRECATED`; removal is deferred until at least 6.0.
+
## Performance
The `/comparisons` folder can be used to run performance tests locally to compare the same output using:
diff --git a/src/Forms/EmailInput.php b/src/Forms/EmailInput.php
index b501f6e..1419ce8 100644
--- a/src/Forms/EmailInput.php
+++ b/src/Forms/EmailInput.php
@@ -15,7 +15,7 @@ class EmailInput implements Stringable
/**
* @var list
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var list
@@ -59,12 +59,18 @@ public function id(string $id): self
/**
* Sets properties on this component's outermost div, not the input.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = array_values($properties);
+ $this->containerProperties = array_values($properties);
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = array_values($properties);
@@ -135,6 +141,6 @@ public function __toString(): string
),
$input,
...[...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/src/Forms/Fieldset.php b/src/Forms/Fieldset.php
index aaf3238..289a542 100644
--- a/src/Forms/Fieldset.php
+++ b/src/Forms/Fieldset.php
@@ -21,7 +21,7 @@ class Fieldset implements Stringable
/**
* @var string[]
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var string[]
@@ -61,12 +61,18 @@ public function elements(string|Stringable ...$elements): self
/**
* Sets properties on this component's outermost element: the fieldset.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = $properties;
+ $this->containerProperties = $properties;
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = $properties;
@@ -96,6 +102,6 @@ public function __toString(): string
return (string) Element::fieldset(
Element::legend($this->label)->props(...$this->labelProperties),
...$elements
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/src/Forms/Password.php b/src/Forms/Password.php
index fe3f984..813c42b 100644
--- a/src/Forms/Password.php
+++ b/src/Forms/Password.php
@@ -17,7 +17,7 @@ class Password implements Stringable
/**
* @var list
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var list
@@ -61,12 +61,18 @@ public function id(string $id): self
/**
* Sets properties on this component's outermost div, not the input.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = array_values($properties);
+ $this->containerProperties = array_values($properties);
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = array_values($properties);
@@ -153,6 +159,6 @@ public function __toString(): string
]),
$input,
...[...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/src/Forms/Select.php b/src/Forms/Select.php
index fdba016..0ebeaf0 100644
--- a/src/Forms/Select.php
+++ b/src/Forms/Select.php
@@ -19,7 +19,7 @@ class Select implements Stringable
/**
* @var list
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var list
@@ -76,12 +76,18 @@ public function id(string $id): self
* Sets properties on the outermost div in dropdown/multiple modes,
* or the fieldset in radio/checkbox modes, not on member controls.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = array_values($properties);
+ $this->containerProperties = array_values($properties);
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = array_values($properties);
@@ -239,7 +245,7 @@ private function selectDropdown(
]),
$select,
...[...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
/**
@@ -288,6 +294,6 @@ private function selectGroup(
return Element::fieldset(
Element::legend($this->label)->props(...$this->labelProperties),
...[...$members, ...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/src/Forms/TextArea.php b/src/Forms/TextArea.php
index a2d69e3..858f6df 100644
--- a/src/Forms/TextArea.php
+++ b/src/Forms/TextArea.php
@@ -15,7 +15,7 @@ class TextArea implements Stringable
/**
* @var list
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var list
@@ -62,12 +62,18 @@ public function id(string $id): self
/**
* Sets properties on this component's outermost div, not the textarea.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = array_values($properties);
+ $this->containerProperties = array_values($properties);
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = array_values($properties);
@@ -136,6 +142,6 @@ public function __toString(): string
]),
$textarea,
...[...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/src/Forms/TextInput.php b/src/Forms/TextInput.php
index 1d81ab0..4b01b3a 100644
--- a/src/Forms/TextInput.php
+++ b/src/Forms/TextInput.php
@@ -15,7 +15,7 @@ class TextInput implements Stringable
/**
* @var list
*/
- private array $wrapperProperties = [];
+ private array $containerProperties = [];
/**
* @var list
@@ -59,12 +59,18 @@ public function id(string $id): self
/**
* Sets properties on this component's outermost div, not the input.
*/
- public function wrapperProps(string ...$properties): self
+ public function containerProps(string ...$properties): self
{
- $this->wrapperProperties = array_values($properties);
+ $this->containerProperties = array_values($properties);
return $this;
}
+ #[\Deprecated(message: 'Use containerProps() instead.', since: '5.0')]
+ public function wrapperProps(string ...$properties): self
+ {
+ return $this->containerProps(...$properties);
+ }
+
public function labelProps(string ...$properties): self
{
$this->labelProperties = array_values($properties);
@@ -133,6 +139,6 @@ public function __toString(): string
]),
$input,
...[...$this->content, $warning]
- )->props(...$this->wrapperProperties);
+ )->props(...$this->containerProperties);
}
}
diff --git a/tests/Forms/ContainerPropsTest.php b/tests/Forms/ContainerPropsTest.php
new file mode 100644
index 0000000..1bab6a8
--- /dev/null
+++ b/tests/Forms/ContainerPropsTest.php
@@ -0,0 +1,68 @@
+ */
+ public static function components(): iterable
+ {
+ foreach (['text', 'email', 'password', 'textarea', 'fieldset', 'dropdown', 'multiple', 'radio', 'checkbox'] as $mode) {
+ yield $mode => [$mode];
+ }
+ }
+
+ #[Test]
+ #[DataProvider('components')]
+ public function deprecated_alias_preserves_fluent_return_and_rendered_output(string $mode): void
+ {
+ $component = match ($mode) {
+ 'text' => TextInput::create('Field', 'field'),
+ 'email' => EmailInput::create('Field', 'field'),
+ 'password' => Password::create('Field', 'field'),
+ 'textarea' => TextArea::create('Field', 'field'),
+ 'fieldset' => Fieldset::create('Field', 'field'),
+ default => Select::create('Field', 'field', ['a' => 'A'])->$mode()
+ };
+ $properties = ['class container', 'data-example preserved'];
+ $modern = clone $component;
+ parent::assertSame($modern, $modern->containerProps(...$properties));
+ $attribute = new ReflectionMethod($component, 'wrapperProps')
+ ->getAttributes(Deprecated::class)[0]->newInstance();
+ parent::assertSame('Use containerProps() instead.', $attribute->message);
+ parent::assertSame('5.0', $attribute->since);
+
+ $deprecations = [];
+ set_error_handler(static function (int $severity, string $message) use (&$deprecations): bool {
+ if ($severity !== E_USER_DEPRECATED) {
+ return false;
+ }
+ $deprecations[] = $message;
+ return true;
+ });
+ try {
+ $result = $component->wrapperProps(...$properties);
+ } finally {
+ restore_error_handler();
+ }
+
+ parent::assertSame($component, $result, 'The deprecated alias must return containerProps() results.');
+ parent::assertSame((string) $modern, (string) $component, 'Renaming must not change markup.');
+ parent::assertCount(1, $deprecations, 'The native attribute must emit one deprecation per call.');
+ parent::assertStringContainsString('Use containerProps() instead.', $deprecations[0]);
+ }
+}
diff --git a/tests/Forms/EmailInputTest.php b/tests/Forms/EmailInputTest.php
index e37d1fc..3eab6ad 100644
--- a/tests/Forms/EmailInputTest.php
+++ b/tests/Forms/EmailInputTest.php
@@ -25,7 +25,7 @@ public function can_set_custom_id(): void // phpcs:ignore
warningMessage: 'Invalid value'
)->id('email-input-id')->content(
Element::p('Helpful text')->props('id email-input-id-help')
- )->wrapperProps('is form-control');
+ )->containerProps('is form-control');
parent::assertSame($expected, $result);
}
diff --git a/tests/Forms/SelectTest.php b/tests/Forms/SelectTest.php
index fa71f59..69c645e 100644
--- a/tests/Forms/SelectTest.php
+++ b/tests/Forms/SelectTest.php
@@ -102,7 +102,7 @@ public function native_attributes_target_controls_and_preserve_generated_identit
'aria-describedby category-help',
...($isGroup ? [] : ['size 4'])
)->content(Element::p('Help')->props('id category-help'))
- ->wrapperProps('class wrapper')->labelProps('class caption')
+ ->containerProps('class wrapper')->labelProps('class caption')
);
$controls = $xpath->query('//*[local-name()="input" or local-name()="select"]');
parent::assertNotFalse($controls);
@@ -193,7 +193,7 @@ public function group_disabling_and_required_attributes_follow_native_semantics(
{
$control = Select::create('Categories', 'categories', ['a' => 'A', 'b' => 'B']);
$xpath = self::controlXpath(
- $control->$mode()->wrapperProps('disabled disabled')->inputProps('required required')
+ $control->$mode()->containerProps('disabled disabled')->inputProps('required required')
);
$isGroup = in_array($mode, ['radio', 'checkbox'], true);
parent::assertSame($isGroup ? 1 : 0, $xpath->query('//*[local-name()="fieldset" and @disabled]')->length);
@@ -437,7 +437,7 @@ public function can_add_properties_to_wrapper(): void // phpcs: ignore
[
'value' => 'display'
]
- )->wrapperProps('id some-id', 'class some-token');
+ )->containerProps('id some-id', 'class some-token');
parent::assertSame($expected, $result);
}
diff --git a/tests/Forms/TextAreaTest.php b/tests/Forms/TextAreaTest.php
index c33d5a1..8d11449 100644
--- a/tests/Forms/TextAreaTest.php
+++ b/tests/Forms/TextAreaTest.php
@@ -124,7 +124,7 @@ public function native_properties_and_custom_identity_target_the_textarea(): voi
'required required',
'readonly readonly',
'disabled disabled'
- )->wrapperProps('class notes-wrapper')->labelProps('class notes-label');
+ )->containerProps('class notes-wrapper')->labelProps('class notes-label');
$xpath = self::xpath($html);
$textarea = $xpath->query('//*[local-name()="textarea"]')->item(0);
parent::assertInstanceOf(DomElement::class, $textarea);
diff --git a/tests/Forms/TextInputTest.php b/tests/Forms/TextInputTest.php
index 6f8fba6..4f4c9b4 100644
--- a/tests/Forms/TextInputTest.php
+++ b/tests/Forms/TextInputTest.php
@@ -25,7 +25,7 @@ public function can_set_custom_id(): void // phpcs:ignore
warningMessage: 'Invalid value'
)->id('text-input-id')->content(
Element::p('Helpful text')->props('id text-input-id-help')
- )->wrapperProps('is form-control');
+ )->containerProps('is form-control');
parent::assertSame($expected, $result);
}