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 Steps

  1. Installation:

    composer require symfony/ux-twig-component
    

    Ensure your config/bundles.php includes Symfony\UX\TwigComponent\TwigComponentBundle::class.

  2. First Component: Create a PHP class with the [AsTwigComponent] attribute:

    // src/Component/AlertComponent.php
    namespace App\Component;
    
    use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
    
    #[AsTwigComponent('alert')]
    class AlertComponent
    {
        public string $message = "Default message";
        public string $type = "info";
    }
    
  3. Template: Create a corresponding Twig template:

    {# templates/components/alert.html.twig #}
    <div class="alert alert-{{ type }}">
        {{ message }}
    </div>
    
  4. Usage in Twig:

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

    Or with HTML syntax:

    <twig:alert message="Hello, world!" type="success" />
    
  5. Autowiring: Symfony automatically registers the component. No manual service configuration is needed for Symfony 5.3+.


First Use Case: Reusable Alert Component

Replace hardcoded alerts in your templates with a reusable AlertComponent. Pass dynamic messages and types (e.g., success, error) as props to maintain consistency across your application.


Implementation Patterns

Core Workflows

1. Component Creation

  • Named Components: Use [AsTwigComponent('name')] for globally reusable components (e.g., alert, card).
  • Anonymous Components: Place a class in src/Component/ and use its directory name as the component name (e.g., src/Component/MyComponent.php<twig:MyComponent />).
  • Dynamic Templates: Override the template path:
    #[AsTwigComponent('alert', template: 'components/custom_alert.html.twig')]
    

2. Props and State

  • Public Properties: Automatically available in Twig:
    public string $title;
    public bool $isOpen = false;
    
    Access in Twig: {{ title }}, {% if isOpen %}.
  • Computed Properties: Use the #[ExposeInTemplate] attribute for getter methods:
    #[ExposeInTemplate]
    public function getFormattedDate(): string {
        return $this->date->format('Y-m-d');
    }
    
    Access in Twig: {{ getFormattedDate() }}.

3. Lifecycle Hooks

  • Pre/Post Mount: Modify props before/after mounting:
    use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
    use Symfony\UX\TwigComponent\Attribute\PostMount;
    
    #[AsTwigComponent('modal')]
    class ModalComponent {
        public bool $isOpen = false;
    
        #[PostMount]
        public function postMount(): void {
            $this->isOpen = true;
        }
    }
    
  • Pre/Post Render: Intercept template rendering:
    use Symfony\UX\TwigComponent\Attribute\PreRender;
    
    #[PreRender]
    public function preRender(): void {
        $this->content = $this->sanitize($this->content);
    }
    

4. Attributes and HTML

  • Component Attributes: Convert extra props to HTML attributes:
    <twig:alert
        message="Hello"
        class="custom-class"
        data-custom="value"
    />
    
    Access in Twig: {{ attributes.add('aria-label', 'Notification') }}.
  • Stimulus Integration: Add controllers dynamically:
    {{ attributes.defaults(stimulus_controller('alert-controller')) }}
    

5. Nested Components

  • Embedded Components: Use {% component %} inside another component’s template.
  • Prop Drilling: Avoid with provide/inject:
    {# Parent template #}
    {% component('parent', {
        provide: { theme: 'dark' }
    }) %}
    
    {# Child template #}
    {{ inject('theme') }} {# Outputs: 'dark' #}
    

Integration Tips

Symfony Ecosystem

  • Stimulus: Combine with @symfony/stimulus-bridge for interactivity:
    <twig:modal {{ attributes.defaults(stimulus_controller('modal-controller')) }}>
        Content here
    </twig:modal>
    
  • Mercure: Use PostMount to subscribe to updates:
    #[PostMount]
    public function postMount(): void {
        $this->hub->subscribe('/updates', $this->handleUpdate(...));
    }
    
  • Forms: Integrate with Symfony Forms by passing form data as props:
    #[AsTwigComponent('user_form')]
    class UserFormComponent {
        public FormInterface $form;
    }
    
    {% component('user_form', { form: form }) %}
    

Testing

  • Unit Tests: Use ComponentTestCase:
    use Symfony\UX\TwigComponent\Test\ComponentTestCase;
    
    class AlertComponentTest extends ComponentTestCase {
        public function testRendering(): void {
            $component = new AlertComponent();
            $component->message = 'Test';
    
            $this->renderComponent($component)
                ->assertSelectorTextContains('div.alert', 'Test');
        }
    }
    
  • Debugging: Use the debug:twig-component command:
    php bin/console debug:twig-component
    

Performance

  • Template Caching: Components leverage Symfony’s Twig cache. Ensure cache_dir is configured in framework.yaml.
  • Profiler: Enable component data collection in config/packages/dev/twig.yaml:
    twig:
        twig_component:
            profiler:
                collect_components: true
    

Gotchas and Tips

Pitfalls

  1. PHP Version Requirements:

    • PHP 8.4+ is mandatory. Avoid using older versions to prevent runtime errors (e.g., attribute parsing failures).
    • Symfony 7.4+ is required. Downgrading may break autowiring or event dispatching.
  2. Attribute Escaping:

    • ComponentAttributes now handles escaping by default. Passing null as an attribute value throws an exception. Use remove() to unset attributes:
      {{ attributes.remove('data-old') }}
      
  3. Template Resolution:

    • Fallback Order: Twig looks for templates in this order:
      1. Explicit template path in [AsTwigComponent].
      2. templates/components/{name}.html.twig.
      3. templates/{name}.html.twig (for anonymous components).
    • Namespaced Components: Use ComponentTemplateFinder for custom logic:
      $finder = new ComponentTemplateFinder($loader, 'custom_namespace');
      
  4. Prop Overrides:

    • Props passed to component() override class defaults, even for readonly properties. Use PostMount to enforce immutability:
      #[PostMount]
      public function postMount(): void {
          if ($this->isReadonly && isset($this->newProp)) {
              throw new \RuntimeException('Cannot modify readonly prop');
          }
      }
      
  5. Stimulus Controllers:

    • Deprecation: The old cva function is removed. Use html_cva from twig/html-extra instead:
      {{ html_cva([
          'class': 'btn btn-' ~ type,
          'data-controller': 'alert',
      ]) }}
      
  6. Debug Mode:

    • Profiler Overhead: Component data collection is enabled by default in debug mode. Disable in production:
      twig_component:
          profiler:
              collect_components: false
      

Debugging Tips

  1. Command Line:

    • List all registered components:
      php bin/console debug:twig-component
      
    • Search for a specific component:
      php bin/console debug:twig-component search alert
      
  2. Twig Errors:

    • Wrap component rendering in try-catch to log errors gracefully:
      {% try %}
          {% component('alert', { message: riskyData }) %}
      {% catch Exception $e %}
          <div class="error">{{ e.message }}</div>
      {% endtry %}
      
  3. Profiler:

    • Inspect component rendering in the Symfony Profiler under the "Twig" tab. Look for:
      • Events: PreMount, PostMount, PreRender, PostRender.
      • Data: Props, attributes, and template paths
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope