Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ux Twig Component Laravel Package

symfony/ux-twig-component

Symfony UX Twig Components lets you bind PHP objects to Twig templates to build reusable UI pieces like alerts, modals, and sidebars. Create small, composable components with clean rendering and better template organization for Symfony apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require symfony/ux-twig-component
    

    Ensure your composer.json meets the requirements: Symfony 7.4+ and PHP 8.4+.

  2. Enable the Twig bundle in config/bundles.php:

    return [
        // ...
        Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
    ];
    
  3. Create your first component:

    // src/Component/AlertComponent.php
    use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
    
    #[AsTwigComponent('alert')]
    class AlertComponent {
        public string $message = 'Default message';
        public string $type = 'info';
    }
    
  4. Create the template at templates/components/alert.html.twig:

    {# templates/components/alert.html.twig #}
    <div class="alert alert-{{ type }}">
        {{ message }}
    </div>
    
  5. Use the component in a template:

    {% component('alert', {
        message: 'Hello, Twig Components!',
        type: 'success'
    }) %}
    

    Or with the HTML syntax:

    <twig:alert message="Hello, Twig Components!" type="success" />
    

First Use Case: Reusable Alert Component

Replace hardcoded alerts in your app with a reusable AlertComponent. Define variants (e.g., success, error) via the $type prop and dynamically pass messages. This reduces template duplication and centralizes styling/logic.


Implementation Patterns

Component Registration

  • Automatic Discovery: Components are auto-discovered via the #[AsTwigComponent] attribute. No manual service registration is needed (Symfony 5.3+ autoconfiguration).
  • Custom Naming: Override the default component name (class name) with the name argument:
    #[AsTwigComponent(name: 'custom_alert')]
    class AlertComponent { ... }
    

Props and State

  • Public Properties as Props: Expose public properties directly in templates (e.g., {{ message }} instead of {{ this.message }}).

  • Computed Properties: Use the #[ExposeInTemplate] attribute to expose private methods/properties:

    #[ExposeInTemplate]
    public function getFormattedMessage(): string {
        return strtoupper($this->message);
    }
    

    Access in Twig: {{ formattedMessage }}.

  • Default Values: Set defaults in the component class:

    public string $message = 'No message provided';
    

Template Resolution

  • Default Location: Templates are resolved from templates/components/{ComponentName}.html.twig.

  • Custom Paths: Override the template path via the template argument in #[AsTwigComponent]:

    #[AsTwigComponent(template: 'path/to/custom_alert.html.twig')]
    
  • Anonymous Components: Use for one-off components without a class:

    {% component('alert', { message: 'Dynamic alert' }) %}
    

    Or with HTML syntax:

    <twig:alert message="Dynamic alert" />
    

Attributes and HTML

  • Dynamic Attributes: Use the attributes variable in templates to render dynamic HTML attributes:
    <div {{ attributes.addClass('custom-class') }}>
        {{ message }}
    </div>
    
  • Stimulus Integration: Add Stimulus controllers via attributes:
    <twig:alert attributes.defaults(stimulus_controller('alert-controller')) />
    

Lifecycle Hooks

  • Pre/Post Mount: Modify component data before/after it’s mounted:
    use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
    use Symfony\UX\TwigComponent\Attribute\Hook;
    
    #[AsTwigComponent]
    class AlertComponent {
        #[Hook('preMount')]
        public function preMount(): void {
            $this->message = 'Modified at preMount!';
        }
    }
    
  • Pre/Post Render: Intercept template rendering:
    #[Hook('preRender')]
    public function preRender(): void {
        $this->template = 'path/to/override.html.twig';
    }
    

State Management with provide/inject

  • Avoid Prop Drilling: Use provide in a parent component to share state with deeply nested children:
    {% component('parent-component') %}
    
    #[AsTwigComponent]
    class ParentComponent {
        public function provide(): array {
            return ['theme' => 'dark'];
        }
    }
    
    Inject in a child:
    #[AsTwigComponent]
    class ChildComponent {
        #[ExposeInTemplate]
        public function getTheme(): string {
            return $this->inject('theme');
        }
    }
    

Testing Components

  • Unit Testing: Use the RenderedComponent class to test rendered output:
    use Symfony\UX\TwigComponent\Test\RenderedComponent;
    
    public function testAlertComponent(): void {
        $component = new AlertComponent();
        $component->message = 'Test message';
        $rendered = RenderedComponent::createFromComponent($component);
        $this->assertStringContainsString('Test message', $rendered->getHtml());
    }
    
  • Debug Command: Inspect registered components:
    php bin/console debug:twig-component
    

Gotchas and Tips

Common Pitfalls

  1. PHP 8.4+ Requirement: Forgetting to upgrade PHP/PHPUnit (e.g., phpunit/dist.xml) will cause failures. Use:

    composer require --dev phpunit/phpunit:^11.0
    

    And update phpunit.xml.dist to use PHP 8.4+.

  2. Template Path Resolution: If templates aren’t found, verify:

    • The template exists at templates/components/{ComponentName}.html.twig.
    • The template argument in #[AsTwigComponent] is correct.
    • No typos in the component name (case-sensitive).
  3. Null Attributes: Passing null to ComponentAttributes throws an exception. Use remove() instead:

    {{ attributes.remove('data-old-attr') }}
    
  4. Stimulus Controllers: If Stimulus features (e.g., stimulus_controller) don’t work, ensure:

    • @symfony/stimulus-bridge is installed.
    • The Stimulus controller is registered in assets/controllers.json.
  5. Debug Mode Overhead: Component data is collected in the profiler by default in debug mode. Disable with:

    # config/packages/dev/twig_component.yaml
    twig_component:
        profiler:
            collect_components: false
    

Debugging Tips

  • Debug Command: List all registered components and their metadata:

    php bin/console debug:twig-component
    

    Search for a specific component:

    php bin/console debug:twig-component search alert
    
  • Profiler Integration: Use the Symfony profiler to inspect component rendering:

    • Navigate to the "Twig" tab in the profiler.
    • Click on "Components" to see rendered components, their props, and execution time.
  • Template Fallback: If a template is missing, Twig falls back to index.html.twig in the same directory. Use this for shared layouts.

Performance Considerations

  • Caching: Component templates are cached like regular Twig templates. Clear the cache after changes:
    php bin/console cache:clear
    
  • Avoid Heavy Logic in Hooks: Prefer lightweight operations in preMount/postMount hooks. Move complex logic to services injected via constructor.

Extension Points

  1. Custom Component Factories: Implement ComponentFactoryInterface to create components dynamically:

    use Symfony\UX\TwigComponent\ComponentFactoryInterface;
    
    class CustomComponentFactory implements ComponentFactoryInterface {
        public function create(string $name, array $props): object {
            return new CustomComponent($props);
        }
    }
    

    Register as a service with the twig.component.factory tag.

  2. Template Finders: Extend ComponentTemplateFinder to support custom template locations (e.g., database-driven templates).

  3. Attribute Escaping: Customize HTML attribute escaping by implementing HtmlAttributeEscaperInterface and passing it to ComponentAttributes.

Migration Notes

  • From ComponentInterface to #[AsTwigComponent]: Update legacy components:
    // Before (Symfony UX 2.x)
    class AlertComponent implements ComponentInterface {
        public static function getComponentName(): string { return 'alert'; }
    }
    
    // After (Symfony UX 3.x)
    #[AsTwigComponent('alert')]
    class AlertComponent { ... }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony