Let's discuss the details around component negotiation and the ergonomics around component replacement.
Extracted from the parent issue
β¨
Single directory components in core
Active
.
Component negotiation
Including a component in a Twig template looks like this:
{{ include('my-component', {
prop1: content.field_foo
}) }}
When Drupal encounters this it will search for all the components with a machine name 'my-component'. The negotiation will choose the component with the following priority rules.
- The component is in the active theme.
- The component is in one of the base themes of the active theme. The closer in the inheritance chain, the more priority.
- The component is in a module.
This intentionally matches the priority rules used for templates sharing the same name.
If the developer wants to skip the negotiation step, they can include the provider in the template name:
{{ include('olivero:my-component', {
prop1: content.field_foo
}) }}
Component replacement
Themes and modules can replace components provided by other themes and modules.
Themes can replace a component by copy & paste of the original component in a location that has higher priority (see Component negotiation). Themes can replace components provided either by modules or by themes which they extend.
Modules can replace components provided by other modules by copy & paste of the original component and explicitly stating it with the "replaces"
property in the component definition file (my-component.component.yml
). Example, the node module wants to replace "my-component"
originally provided by system
. node/templates/components/foo/bar/my-component/my-component.component.yml
needs to contain: replaces: 'system:my-component'
Additional considerations
We decided against always prefixing components with the provider. This will better reflect the developer's decision of embedding a component leveraging the negotiation rules. Adding the provider in front will have the effect of including the component as defined in the specified provider.
We thought it would be confusing to allow writing {{ include('system:my-component') }}
yet render the my-component
as defined in a sub-theme of Olivero, so we decided against it.
No prefix when including/embedding means "let the negotiation decide the component to render". Adding the prefix will skip negotiation entirely.