diff --git a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php index 4c7c5a419fa..0ae52de620b 100644 --- a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php +++ b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php @@ -274,7 +274,7 @@ public function testCanDehydrateAndHydrateComponentsWithAttributes(): void $factory = self::getContainer()->get('ux.twig_component.component_factory'); /** @var ComponentWithAttributes $component */ - $component = $factory->create('with_attributes', $attributes = ['class' => 'foo']); + $component = $factory->create('with_attributes', $attributes = ['class' => 'foo', 'value' => null]); $this->assertSame($attributes, $component->attributes->all()); diff --git a/src/TwigComponent/src/ComponentAttributes.php b/src/TwigComponent/src/ComponentAttributes.php index 3ce8b211ff7..02d0445c1da 100644 --- a/src/TwigComponent/src/ComponentAttributes.php +++ b/src/TwigComponent/src/ComponentAttributes.php @@ -30,7 +30,13 @@ public function __toString(): string { return array_reduce( array_keys($this->attributes), - fn (string $carry, string $key) => sprintf('%s %s="%s"', $carry, $key, $this->attributes[$key]), + function (string $carry, string $key) { + if (null === $this->attributes[$key]) { + return "{$carry} {$key}"; + } + + return sprintf('%s %s="%s"', $carry, $key, $this->attributes[$key]); + }, '' ); } diff --git a/src/TwigComponent/src/HasAttributesTrait.php b/src/TwigComponent/src/HasAttributesTrait.php index 3b8f917a85b..ea7877c7688 100644 --- a/src/TwigComponent/src/HasAttributesTrait.php +++ b/src/TwigComponent/src/HasAttributesTrait.php @@ -45,8 +45,8 @@ public function mountAttributes(array $data): array } foreach ($data as $key => $value) { - if (!is_scalar($value)) { - throw new \LogicException(sprintf('Unable to use "%s" (%s) as an attribute. Attributes must be scalar. If you meant to mount this value on your component, make sure this is a writable property.', $key, get_debug_type($value))); + if (!is_scalar($value) && null !== $value) { + throw new \LogicException(sprintf('Unable to use "%s" (%s) as an attribute. Attributes must be scalar or null. If you meant to mount this value on your component, make sure this is a writable property.', $key, get_debug_type($value))); } } diff --git a/src/TwigComponent/src/Resources/doc/index.rst b/src/TwigComponent/src/Resources/doc/index.rst index 83166afc391..7629815a567 100644 --- a/src/TwigComponent/src/Resources/doc/index.rst +++ b/src/TwigComponent/src/Resources/doc/index.rst @@ -454,6 +454,19 @@ When rendering the component, you can pass an array of html attributes to add: My Component! +Set an attribute's value to ``null`` to exclude the value when rendering: + +.. code-block:: twig + + {# templates/components/my_component.html.twig #} + + + {# render component #} + {{ component('my_component', { type: 'text', value: '', autofocus: null }) }} + + {# renders as: #} + + Defaults & Merging ~~~~~~~~~~~~~~~~~~ diff --git a/src/TwigComponent/tests/Fixtures/templates/template_a.html.twig b/src/TwigComponent/tests/Fixtures/templates/template_a.html.twig index e349315440d..213a8a5b83a 100644 --- a/src/TwigComponent/tests/Fixtures/templates/template_a.html.twig +++ b/src/TwigComponent/tests/Fixtures/templates/template_a.html.twig @@ -1,3 +1,3 @@ {{ component('component_a', { propA: 'prop a value', propB: 'prop b value' }) }} -{{ component('with_attributes', { prop: 'prop value 1', class: 'bar', style: 'color:red;' }) }} +{{ component('with_attributes', { prop: 'prop value 1', class: 'bar', style: 'color:red;', value: '', autofocus: null }) }} {{ component('with_attributes', { prop: 'prop value 2', attributes: { class: 'baz' }, type: 'submit', style: 'color:red;' }) }} diff --git a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php index 8003e8fb417..ca5497e53f7 100644 --- a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php +++ b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php @@ -60,7 +60,7 @@ public function testCanRenderComponentWithAttributes(): void $output = self::getContainer()->get(Environment::class)->render('template_a.html.twig'); $this->assertStringContainsString('Component Content (prop value 1)', $output); - $this->assertStringContainsString('