|
| 1 | +# Passing Parameters to Components |
| 2 | + |
| 3 | +django-bird provides two ways to pass parameters to your components: attributes and properties. While attributes and properties may look similar when using a component, they serve different purposes. |
| 4 | + |
| 5 | +Attributes are made available to your component template as a flattened string via the `{{ attrs }}` template context variable which can be used to apply HTML attributes to elements, while properties are accessible as individual values (e.g. `{{ props.variant }}`) that your component can use internally to control its rendering logic. |
| 6 | + |
| 7 | +Note that these parameters are distinct from [Slots](slots.md) - they are used to configured how your component behaves or renders, while slots define where content should be inserted into your component's template. |
| 8 | + |
| 9 | +For example, a button component might use properties to control its styling and attributes to set HTML attributes, while using slots to define its content: |
| 10 | + |
| 11 | +```htmldjango |
| 12 | +{% bird button variant="primary" data-analytics="signup" %} |
| 13 | + Click here {# This content will go in the default slot #} |
| 14 | +{% endbird %} |
| 15 | +``` |
| 16 | + |
| 17 | +## Attributes |
| 18 | + |
| 19 | +Attributes (i.e. `attrs`) let you pass additional HTML attributes to your components. This feature provides flexibility and customization without modifying the component template. |
| 20 | + |
| 21 | +In your component template, the `{{ attrs }}` variable is a special variable that contains all the attributes passed to the component as a pre-rendered string. Unlike props which can be accessed individually, attributes are flattened into a single string ready to be inserted into an HTML element. The `{{ attrs }}` variable automatically handles both key-value attributes (like `class="btn"`) and boolean attributes (like `disabled`). |
| 22 | + |
| 23 | +### Basic Usage |
| 24 | + |
| 25 | +Here's a simple example of a button component that accepts attributes: |
| 26 | + |
| 27 | +```{code-block} htmldjango |
| 28 | +:caption: templates/bird/button.html |
| 29 | +
|
| 30 | +<button {{ attrs }}> |
| 31 | + {{ slot }} |
| 32 | +</button> |
| 33 | +``` |
| 34 | + |
| 35 | +Use this component and pass attributes like this: |
| 36 | + |
| 37 | +```htmldjango |
| 38 | +{% bird button class="btn" %} |
| 39 | + Click me! |
| 40 | +{% endbird %} |
| 41 | +``` |
| 42 | + |
| 43 | +It will render as: |
| 44 | + |
| 45 | +```html |
| 46 | +<button class="btn"> |
| 47 | + Click me! |
| 48 | +</button> |
| 49 | + |
| 50 | +``` |
| 51 | + |
| 52 | +### Multiple Attributes |
| 53 | + |
| 54 | +You can pass multiple attributes to a component: |
| 55 | + |
| 56 | +```htmldjango |
| 57 | +{% bird button class="btn btn-primary" id="submit-btn" disabled %} |
| 58 | + Submit |
| 59 | +{% endbird %} |
| 60 | +``` |
| 61 | + |
| 62 | +This will render as: |
| 63 | + |
| 64 | +```html |
| 65 | +<button class="btn btn-primary" id="submit-btn" disabled> |
| 66 | + Submit |
| 67 | +</button> |
| 68 | +``` |
| 69 | + |
| 70 | +## Properties |
| 71 | + |
| 72 | +Properties (i.e. `props`) allow you to define parameters that your component expects, with optional default values. Unlike attributes which are provided as a flattened string via `{{ attrs }}`, props are processed by the component and made available as individual values (e.g. `{{ props.variant }}`) that can be used to control rendering logic. |
| 73 | + |
| 74 | +In your component template, props are defined using the `{% bird:prop %}` tag and accessed via the `{{ props }}` context variable. You can define as many props as needed using separate `{% bird:prop %}` tags. When a prop is defined, any matching attribute passed to the component will be removed from `{{ attrs }}` and made available in `{{ props }}` instead. |
| 75 | + |
| 76 | +### Basic Usage |
| 77 | + |
| 78 | +Here's a simple example of a button component that uses props: |
| 79 | + |
| 80 | +```{code-block} htmldjango |
| 81 | +:caption: templates/bird/button.html |
| 82 | +
|
| 83 | +{% bird:prop variant='primary' %} |
| 84 | +<button class="btn btn-{{ props.variant }}" {{ attrs }}> |
| 85 | + {{ slot }} |
| 86 | +</button> |
| 87 | +``` |
| 88 | + |
| 89 | +Use this component and override the default variant like this: |
| 90 | + |
| 91 | +```htmldjango |
| 92 | +{% bird button variant="secondary" id="secondary-button" %} |
| 93 | + Click me! |
| 94 | +{% endbird %} |
| 95 | +``` |
| 96 | + |
| 97 | +It will render as: |
| 98 | + |
| 99 | +```html |
| 100 | +<button class="btn btn-secondary" id="secondary-button"> |
| 101 | + Click me! |
| 102 | +</button> |
| 103 | +``` |
| 104 | + |
| 105 | +Notice how this works: |
| 106 | + |
| 107 | +- The `variant` attribute is removed from `attrs` because it matches a defined prop |
| 108 | +- Its value "secondary" is made available as `props.variant` |
| 109 | +- The `id` attribute remains in `attrs` since it's not defined as a prop |
| 110 | +- The final HTML only includes `variant`'s value as part of the class name, while `id` appears as a direct attribute |
| 111 | + |
| 112 | +This separation allows you to use props to control your component's logic while still accepting arbitrary HTML attributes. |
| 113 | + |
| 114 | +### Multiple Props |
| 115 | + |
| 116 | +Components often need multiple props to control different aspects of their behavior. Each prop is defined with its own `{% bird:prop %}` tag: |
| 117 | + |
| 118 | +```{code-block} htmldjango |
| 119 | +:caption: templates/bird/button.html |
| 120 | +
|
| 121 | +{% bird:prop variant='primary' %} |
| 122 | +{% bird:prop size='md' %} |
| 123 | +<button |
| 124 | + class="btn btn-{{ props.variant }} btn-{{ props.size }}" |
| 125 | + {{ attrs }} |
| 126 | +> |
| 127 | + {{ slot }} |
| 128 | +</button> |
| 129 | +``` |
| 130 | + |
| 131 | +Use the component by setting any combination of these props: |
| 132 | + |
| 133 | +```htmldjango |
| 134 | +{% bird button variant="secondary" size="lg" disabled=True %} |
| 135 | + Click me! |
| 136 | +{% endbird %} |
| 137 | +``` |
| 138 | + |
| 139 | +It will render as: |
| 140 | + |
| 141 | +```html |
| 142 | +<button class="btn btn-secondary btn-lg" disabled> |
| 143 | + Click me! |
| 144 | +</button> |
| 145 | +``` |
| 146 | + |
| 147 | +This approach of using separate tags for each prop makes it easier to expand the prop system in the future - for example, adding features like type validation or choice constraints while maintaining a clean syntax. |
| 148 | + |
| 149 | +### Props with Defaults |
| 150 | + |
| 151 | +Props can be defined with or without default values: |
| 152 | + |
| 153 | +```htmldjango |
| 154 | +{% bird:prop id %} {# No default value #} |
| 155 | +{% bird:prop variant='primary' %} {# With default value #} |
| 156 | +<button |
| 157 | + id="{{ props.id }}" |
| 158 | + class="btn btn-{{ props.variant }}" |
| 159 | + {{ attrs }} |
| 160 | +> |
| 161 | + {{ slot }} |
| 162 | +</button> |
| 163 | +``` |
| 164 | + |
| 165 | +When used, props will take their value from either the passed attribute or fall back to their default: |
| 166 | + |
| 167 | +```htmldjango |
| 168 | +{% bird button variant="secondary" %} |
| 169 | + Submit |
| 170 | +{% endbird %} |
| 171 | +``` |
| 172 | + |
| 173 | +This will render as: |
| 174 | + |
| 175 | +```html |
| 176 | +<button id="" class="btn btn-secondary"> |
| 177 | + Submit |
| 178 | +</button> |
| 179 | +``` |
| 180 | + |
| 181 | +```{note} |
| 182 | +Props defined without a default value will render as an empty string if no value is provided when using the component. This behavior may change in a future version to either require default values or handle undefined props differently. |
| 183 | +``` |
0 commit comments