API¤
BaseNode ¤
BaseNode(
params: List[TagAttr],
flags: Optional[Dict[str, bool]] = None,
nodelist: Optional[NodeList] = None,
node_id: Optional[str] = None,
contents: Optional[str] = None,
template_name: Optional[str] = None,
template_component: Optional[Type[Component]] = None,
)
Bases: django.template.base.Node
Node class for all django-components custom template tags.
This class has a dual role:
-
It declares how a particular template tag should be parsed - By setting the
tag
,end_tag
, andallowed_flags
attributes:This will allow the template tag
{% slot %}
to be used like this: -
The
render
method is the actual implementation of the template tag.This is where the tag's logic is implemented:
class MyNode(BaseNode): tag = "mynode" def render(self, context: Context, name: str, **kwargs: Any) -> str: return f"Hello, {name}!"
This will allow the template tag
{% mynode %}
to be used like this:
The template tag accepts parameters as defined on the render
method's signature.
For more info, see BaseNode.render()
.
Methods:
-
parse
– -
register
– -
render
– -
unregister
–
Attributes:
-
active_flags
(List[str]
) – -
allowed_flags
(Optional[List[str]]
) – -
contents
(Optional[str]
) – -
end_tag
(Optional[str]
) – -
flags
(Dict[str, bool]
) – -
node_id
(str
) – -
nodelist
(NodeList
) – -
params
(List[TagAttr]
) – -
tag
(str
) – -
template_component
(Optional[Type[Component]]
) – -
template_name
(Optional[str]
) –
active_flags property
¤
Flags that were set for this specific instance as a list of strings.
E.g. the following tag:
Will have the following flags:
allowed_flags class-attribute
¤
The list of all possible flags for this tag.
E.g. ["required"]
will allow this tag to be used like {% slot required %}
.
This will allow the template tag {% slot %}
to be used like this:
contents instance-attribute
¤
The contents of the tag.
This is the text between the opening and closing tags, e.g.
The contents
will be "<div> ... </div>"
.
end_tag class-attribute
¤
The end tag name.
E.g. "endcomponent"
or "endslot"
will make this class match template tags {% endcomponent %}
or {% endslot %}
.
This will allow the template tag {% slot %}
to be used like this:
If not set, then this template tag has no end tag.
So instead of {% component %} ... {% endcomponent %}
, you'd use only {% component %}
.
flags instance-attribute
¤
Dictionary of all allowed_flags
that were set on the tag.
Flags that were set are True
, and the rest are False
.
E.g. the following tag:
Has 2 flags, default
and required
, but only default
was set.
The flags
dictionary will be:
You can check if a flag is set by doing:
node_id instance-attribute
¤
node_id: str = node_id or gen_id()
The unique ID of the node.
Extensions can use this ID to store additional information.
nodelist instance-attribute
¤
The nodelist of the tag.
This is the text between the opening and closing tags, e.g.
The nodelist
will contain the <div> ... </div>
part.
Unlike contents
, the nodelist
contains the actual Nodes, not just the text.
params instance-attribute
¤
params: List[TagAttr] = params
The parameters to the tag in the template.
A single param represents an arg or kwarg of the template tag.
E.g. the following tag:
Has 3 params:
- Posiitonal arg
"my_comp"
- Keyword arg
key=val
- Keyword arg
key2='val2 two'
tag class-attribute
¤
tag: str
The tag name.
E.g. "component"
or "slot"
will make this class match template tags {% component %}
or {% slot %}
.
This will allow the template tag {% slot %}
to be used like this:
template_component instance-attribute
¤
template_name instance-attribute
¤
The name of the Template
that contains this node.
The template name is set by Django's template loaders.
For example, the filesystem template loader will set this to the absolute path of the template file.
parse classmethod
¤
This function is what is passed to Django's Library.tag()
when registering the tag.
In other words, this method is called by Django's template parser when we encounter a tag that matches this node's tag, e.g. {% component %}
or {% slot %}
.
To register the tag, you can use BaseNode.register()
.
register classmethod
¤
A convenience method for registering the tag with the given library.
Allows you to then use the node in templates like so:
render ¤
Render the node. This method is meant to be overridden by subclasses.
The signature of this function decides what input the template tag accepts.
The render()
method MUST accept a context
argument. Any arguments after that will be part of the tag's input parameters.
So if you define a render
method like this:
Then the tag will require the name
parameter, and accept any extra keyword arguments:
unregister classmethod
¤
Unregisters the node from the given library.
CommandLiteralAction module-attribute
¤
CommandLiteralAction = Literal['append', 'append_const', 'count', 'extend', 'store', 'store_const', 'store_true', 'store_false', 'version']
The basic type of action to be taken when this argument is encountered at the command line.
This is a subset of the values for action
in ArgumentParser.add_argument()
.
Component ¤
Component(
registered_name: Optional[str] = None,
outer_context: Optional[Context] = None,
registry: Optional[ComponentRegistry] = None,
context: Optional[Context] = None,
args: Optional[Any] = None,
kwargs: Optional[Any] = None,
slots: Optional[Any] = None,
deps_strategy: Optional[DependenciesStrategy] = None,
request: Optional[HttpRequest] = None,
node: Optional[ComponentNode] = None,
id: Optional[str] = None,
)
Methods:
-
as_view
– -
get_context_data
– -
get_css_data
– -
get_js_data
– -
get_template
– -
get_template_data
– -
get_template_name
– -
inject
– -
on_render
– -
on_render_after
– -
on_render_before
– -
render
– -
render_to_response
–
Attributes:
-
Args
(Optional[Type]
) – -
Cache
(Type[ComponentCache]
) – -
CssData
(Optional[Type]
) – -
DebugHighlight
(Type[ComponentDebugHighlight]
) – -
Defaults
(Type[ComponentDefaults]
) – -
JsData
(Optional[Type]
) – -
Kwargs
(Optional[Type]
) – -
Media
(Optional[Type[ComponentMediaInput]]
) – -
Slots
(Optional[Type]
) – -
TemplateData
(Optional[Type]
) – -
View
(Type[ComponentView]
) – -
args
(Any
) – -
cache
(ComponentCache
) – -
class_id
(str
) – -
context
(Context
) – -
context_processors_data
(Dict
) – -
css
(Optional[str]
) – -
css_file
(Optional[str]
) – -
debug_highlight
(ComponentDebugHighlight
) – -
defaults
(ComponentDefaults
) – -
deps_strategy
(DependenciesStrategy
) – -
do_not_call_in_templates
(bool
) – -
id
(str
) – -
input
(ComponentInput
) – -
is_filled
(SlotIsFilled
) – -
js
(Optional[str]
) – -
js_file
(Optional[str]
) – -
kwargs
(Any
) – -
media
(Optional[Media]
) – -
media_class
(Type[Media]
) – -
name
(str
) – -
node
(Optional[ComponentNode]
) – -
outer_context
(Optional[Context]
) – -
raw_args
(List[Any]
) – -
raw_kwargs
(Dict[str, Any]
) – -
raw_slots
(Dict[str, Slot]
) – -
registered_name
(Optional[str]
) – -
registry
(ComponentRegistry
) – -
request
(Optional[HttpRequest]
) – -
response_class
(Type[HttpResponse]
) – -
slots
(Any
) – -
template
(Optional[str]
) – -
template_file
(Optional[str]
) – -
template_name
(Optional[str]
) – -
view
(ComponentView
) –
Args class-attribute
¤
Optional typing for positional arguments passed to the component.
If set and not None
, then the args
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class Args(NamedTuple):
color: str
size: int
def get_template_data(self, args: Args, kwargs, slots, context):
assert isinstance(args, Table.Args)
return {
"color": args.color,
"size": args.size,
}
The constructor of this class MUST accept positional arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
.
Use Args
to:
- Validate the input at runtime.
- Set type hints for the positional arguments for data methods like
get_template_data()
. - Document the component inputs.
You can also use Args
to validate the positional arguments for Component.render()
:
Read more on Typing and validation.
Cache class-attribute
¤
Cache: Type[ComponentCache]
The fields of this class are used to configure the component caching.
Read more about Component caching.
Example:
CssData class-attribute
¤
Optional typing for the data to be returned from get_css_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_css_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
You can also return an instance of CssData
directly from get_css_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class CssData(NamedTuple):
color: str
size: int
def get_css_data(self, args, kwargs, slots, context):
return Table.CssData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use CssData
to:
- Validate the data returned from
get_css_data()
at runtime. - Set type hints for this data.
- Document the component data.
Read more on Typing and validation.
Info
If you use a custom class for CssData
, this class needs to be convertable to a dictionary.
You can implement either:
-
_asdict()
method -
Or make the class dict-like with
__iter__()
and__getitem__()
DebugHighlight class-attribute
¤
DebugHighlight: Type[ComponentDebugHighlight]
The fields of this class are used to configure the component debug highlighting.
Read more about Component debug highlighting.
Defaults class-attribute
¤
Defaults: Type[ComponentDefaults]
The fields of this class are used to set default values for the component's kwargs.
Read more about Component defaults.
Example:
JsData class-attribute
¤
Optional typing for the data to be returned from get_js_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_js_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
You can also return an instance of JsData
directly from get_js_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class JsData(NamedTuple):
color: str
size: int
def get_js_data(self, args, kwargs, slots, context):
return Table.JsData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use JsData
to:
- Validate the data returned from
get_js_data()
at runtime. - Set type hints for this data.
- Document the component data.
Read more on Typing and validation.
Info
If you use a custom class for JsData
, this class needs to be convertable to a dictionary.
You can implement either:
-
_asdict()
method -
Or make the class dict-like with
__iter__()
and__getitem__()
Kwargs class-attribute
¤
Optional typing for keyword arguments passed to the component.
If set and not None
, then the kwargs
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class Kwargs(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs: Kwargs, slots, context):
assert isinstance(kwargs, Table.Kwargs)
return {
"color": kwargs.color,
"size": kwargs.size,
}
The constructor of this class MUST accept keyword arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use Kwargs
to:
- Validate the input at runtime.
- Set type hints for the keyword arguments for data methods like
get_template_data()
. - Document the component inputs.
You can also use Kwargs
to validate the keyword arguments for Component.render()
:
Read more on Typing and validation.
Media class-attribute
¤
Media: Optional[Type[ComponentMediaInput]] = None
Defines JS and CSS media files associated with this component.
This Media
class behaves similarly to Django's Media class:
- Paths are generally handled as static file paths, and resolved URLs are rendered to HTML with
media_class.render_js()
ormedia_class.render_css()
. - A path that starts with
http
,https
, or/
is considered a URL, skipping the static file resolution. This path is still rendered to HTML withmedia_class.render_js()
ormedia_class.render_css()
. - A
SafeString
(with__html__
method) is considered an already-formatted HTML tag, skipping both static file resolution and rendering withmedia_class.render_js()
ormedia_class.render_css()
. - You can set
extend
to configure whether to inherit JS / CSS from parent components. See Media inheritance.
However, there's a few differences from Django's Media class:
- Our Media class accepts various formats for the JS and CSS files: either a single file, a list, or (CSS-only) a dictionary (See
ComponentMediaInput
). - Individual JS / CSS files can be any of
str
,bytes
,Path
,SafeString
, or a function (SeeComponentMediaInputPath
).
Example:
Slots class-attribute
¤
Optional typing for slots passed to the component.
If set and not None
, then the slots
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component, Slot, SlotInput
class Table(Component):
class Slots(NamedTuple):
header: SlotInput
footer: Slot
def get_template_data(self, args, kwargs, slots: Slots, context):
assert isinstance(slots, Table.Slots)
return {
"header": slots.header,
"footer": slots.footer,
}
The constructor of this class MUST accept keyword arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use Slots
to:
- Validate the input at runtime.
- Set type hints for the slots for data methods like
get_template_data()
. - Document the component inputs.
You can also use Slots
to validate the slots for Component.render()
:
Read more on Typing and validation.
Info
Components can receive slots as strings, functions, or instances of Slot
.
Internally these are all normalized to instances of Slot
.
Therefore, the slots
dictionary available in data methods (like get_template_data()
) will always be a dictionary of Slot
instances.
To correctly type this dictionary, you should set the fields of Slots
to Slot
or SlotInput
:
SlotInput
is a union of Slot
, string, and function types.
TemplateData class-attribute
¤
Optional typing for the data to be returned from get_template_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_template_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
You can also return an instance of TemplateData
directly from get_template_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class TemplateData(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs, slots, context):
return Table.TemplateData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use TemplateData
to:
- Validate the data returned from
get_template_data()
at runtime. - Set type hints for this data.
- Document the component data.
Read more on Typing and validation.
Info
If you use a custom class for TemplateData
, this class needs to be convertable to a dictionary.
You can implement either:
-
_asdict()
method -
Or make the class dict-like with
__iter__()
and__getitem__()
View class-attribute
¤
View: Type[ComponentView]
The fields of this class are used to configure the component views and URLs.
This class is a subclass of django.views.View
. The Component
instance is available via self.component
.
Override the methods of this class to define the behavior of the component.
Read more about Component views and URLs.
Example:
args instance-attribute
¤
args: Any
Positional arguments passed to the component.
This is part of the Render API.
args
has the same behavior as the args
argument of Component.get_template_data()
:
- If you defined the
Component.Args
class, then theargs
property will return an instance of thatArgs
class. - Otherwise,
args
will be a plain list.
Example:
With Args
class:
from django_components import Component
class Table(Component):
class Args(NamedTuple):
page: int
per_page: int
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.args.page == 123
assert self.args.per_page == 10
rendered = Table.render(
args=[123, 10],
)
Without Args
class:
cache instance-attribute
¤
cache: ComponentCache
Instance of ComponentCache
available at component render time.
class_id class-attribute
¤
class_id: str
Unique ID of the component class, e.g. MyComponent_ab01f2
.
This is derived from the component class' module import path, e.g. path.to.my.MyComponent
.
context instance-attribute
¤
The context
argument as passed to Component.get_template_data()
.
This is Django's Context with which the component template is rendered.
If the root component or template was rendered with RequestContext
then this will be an instance of RequestContext
.
Whether the context variables defined in context
are available to the template depends on the context behavior mode:
-
In
"django"
context behavior mode, the template will have access to the keys of this context. -
In
"isolated"
context behavior mode, the template will NOT have access to this context, and data MUST be passed via component's args and kwargs.
context_processors_data property
¤
context_processors_data: Dict
Retrieve data injected by context_processors
.
This data is also available from within the component's template, without having to return this data from get_template_data()
.
In regular Django templates, you need to use RequestContext
to apply context processors.
In Components, the context processors are applied to components either when:
- The component is rendered with
RequestContext
(Regular Django behavior) - The component is rendered with a regular
Context
(or none), but therequest
kwarg ofComponent.render()
is set. - The component is nested in another component that matches any of these conditions.
See Component.request
on how the request
(HTTPRequest) object is passed to and within the components.
NOTE: This dictionary is generated dynamically, so any changes to it will not be persisted.
Example:
css class-attribute
instance-attribute
¤
Main CSS associated with this component inlined as string.
Example:
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.css
.
Learn more about syntax highlighting.
css_file class-attribute
¤
Main CSS associated with this component as file path.
The filepath must be either:
- Relative to the directory where the Component's Python file is defined.
- Relative to one of the component directories, as set by
COMPONENTS.dirs
orCOMPONENTS.app_dirs
(e.g.<root>/components/
). - Relative to the staticfiles directories, as set by Django's
STATICFILES_DIRS
setting (e.g.<root>/static/
).
When you create a Component class with css_file
, these will happen:
- If the file path is relative to the directory where the component's Python file is, the path is resolved.
- The file is read and its contents is set to
Component.css
.
Example:
defaults instance-attribute
¤
defaults: ComponentDefaults
Instance of ComponentDefaults
available at component render time.
deps_strategy instance-attribute
¤
deps_strategy: DependenciesStrategy
Dependencies strategy defines how to handle JS and CSS dependencies of this and child components.
Read more about Dependencies rendering.
This is part of the Render API.
There are six strategies:
"document"
(default)- Smartly inserts JS / CSS into placeholders or into
<head>
and<body>
tags. - Inserts extra script to allow
fragment
types to work. - Assumes the HTML will be rendered in a JS-enabled browser.
- Smartly inserts JS / CSS into placeholders or into
"fragment"
- A lightweight HTML fragment to be inserted into a document with AJAX.
- No JS / CSS included.
"simple"
- Smartly insert JS / CSS into placeholders or into
<head>
and<body>
tags. - No extra script loaded.
- Smartly insert JS / CSS into placeholders or into
"prepend"
- Insert JS / CSS before the rendered HTML.
- No extra script loaded.
"append"
- Insert JS / CSS after the rendered HTML.
- No extra script loaded.
"ignore"
- HTML is left as-is. You can still process it with a different strategy later with
render_dependencies()
. - Used for inserting rendered HTML into other components.
- HTML is left as-is. You can still process it with a different strategy later with
do_not_call_in_templates class-attribute
¤
do_not_call_in_templates: bool = True
Django special property to prevent calling the instance as a function inside Django templates.
Read more about Django's do_not_call_in_templates
.
id instance-attribute
¤
id: str
This ID is unique for every time a Component.render()
(or equivalent) is called (AKA "render ID").
This is useful for logging or debugging.
The ID is a 7-letter alphanumeric string in the format cXXXXXX
, where XXXXXX
is a random string of 6 alphanumeric characters (case-sensitive).
E.g. c1A2b3c
.
A single render ID has a chance of collision 1 in 57 billion. However, due to birthday paradox, the chance of collision increases to 1% when approaching ~33K render IDs.
Thus, there is currently a soft-cap of ~30K components rendered on a single page.
If you need to expand this limit, please open an issue on GitHub.
Example:
input instance-attribute
¤
input: ComponentInput
Deprecated. Will be removed in v1.
Input holds the data that were passed to the current component at render time.
This includes:
args
- List of positional argumentskwargs
- Dictionary of keyword argumentsslots
- Dictionary of slots. Values are normalized toSlot
instancescontext
-Context
object that should be used to render the component- And other kwargs passed to
Component.render()
likedeps_strategy
Example:
class Table(Component):
def get_template_data(self, args, kwargs, slots, context):
# Access component's inputs, slots and context
assert self.args == [123, "str"]
assert self.kwargs == {"variable": "test", "another": 1}
footer_slot = self.slots["footer"]
some_var = self.input.context["some_var"]
rendered = TestComponent.render(
kwargs={"variable": "test", "another": 1},
args=[123, "str"],
slots={"footer": "MY_SLOT"},
)
is_filled instance-attribute
¤
Deprecated. Will be removed in v1. Use Component.slots
instead. Note that Component.slots
no longer escapes the slot names.
Dictionary describing which slots have or have not been filled.
This attribute is available for use only within:
You can also access this variable from within the template as
js class-attribute
instance-attribute
¤
Main JS associated with this component inlined as string.
Example:
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.js
.
Learn more about syntax highlighting.
js_file class-attribute
¤
Main JS associated with this component as file path.
The filepath must be either:
- Relative to the directory where the Component's Python file is defined.
- Relative to one of the component directories, as set by
COMPONENTS.dirs
orCOMPONENTS.app_dirs
(e.g.<root>/components/
). - Relative to the staticfiles directories, as set by Django's
STATICFILES_DIRS
setting (e.g.<root>/static/
).
When you create a Component class with js_file
, these will happen:
- If the file path is relative to the directory where the component's Python file is, the path is resolved.
- The file is read and its contents is set to
Component.js
.
Example:
kwargs instance-attribute
¤
kwargs: Any
Keyword arguments passed to the component.
This is part of the Render API.
kwargs
has the same behavior as the kwargs
argument of Component.get_template_data()
:
- If you defined the
Component.Kwargs
class, then thekwargs
property will return an instance of thatKwargs
class. - Otherwise,
kwargs
will be a plain dict.
Example:
With Kwargs
class:
from django_components import Component
class Table(Component):
class Kwargs(NamedTuple):
page: int
per_page: int
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.kwargs.page == 123
assert self.kwargs.per_page == 10
rendered = Table.render(
kwargs={
"page": 123,
"per_page": 10,
},
)
Without Kwargs
class:
media class-attribute
instance-attribute
¤
media: Optional[Media] = None
Normalized definition of JS and CSS media files associated with this component. None
if Component.Media
is not defined.
This field is generated from Component.media_class
.
Read more on Accessing component's HTML / JS / CSS.
Example:
media_class class-attribute
¤
media_class: Type[Media] = Media
Set the Media class that will be instantiated with the JS and CSS media files from Component.Media
.
This is useful when you want to customize the behavior of the media files, like customizing how the JS or CSS files are rendered into <script>
or <link>
HTML tags.
Read more in Defining HTML / JS / CSS files.
Example:
name instance-attribute
¤
name: str
The name of the component.
If the component was registered, this will be the name under which the component was registered in the ComponentRegistry
.
Otherwise, this will be the name of the class.
Example:
@register("my_component")
class RegisteredComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.name, # "my_component"
}
class UnregisteredComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.name, # "UnregisteredComponent"
}
node instance-attribute
¤
node: Optional[ComponentNode]
The ComponentNode
instance that was used to render the component.
This will be set only if the component was rendered with the {% component %}
tag.
Accessing the ComponentNode
is mostly useful for extensions, which can modify their behaviour based on the source of the Component.
class MyComponent(Component):
def get_template_data(self, context, template):
if self.node is not None:
assert self.node.name == "my_component"
For example, if MyComponent
was used in another component - that is, with a {% component "my_component" %}
tag in a template that belongs to another component - then you can use self.node.template_component
to access the owner Component
class.
class Parent(Component):
template: types.django_html = '''
<div>
{% component "my_component" / %}
</div>
'''
@register("my_component")
class MyComponent(Component):
def get_template_data(self, context, template):
if self.node is not None:
assert self.node.template_component == Parent
Info
Component.node
is None
if the component is created by Component.render()
(but you can pass in the node
kwarg yourself).
outer_context instance-attribute
¤
outer_context: Optional[Context]
When a component is rendered with the {% component %}
tag, this is the Django's Context
object that was used just outside of the component.
{% with abc=123 %}
{{ abc }} {# <--- This is in outer context #}
{% component "my_component" / %}
{% endwith %}
This is relevant when your components are isolated, for example when using the "isolated" context behavior mode or when using the only
flag.
When components are isolated, each component has its own instance of Context, so outer_context
is different from the context
argument.
raw_args instance-attribute
¤
Positional arguments passed to the component.
This is part of the Render API.
Unlike Component.args
, this attribute is not typed and will remain as plain list even if you define the Component.Args
class.
Example:
raw_kwargs instance-attribute
¤
Keyword arguments passed to the component.
This is part of the Render API.
Unlike Component.kwargs
, this attribute is not typed and will remain as plain dict even if you define the Component.Kwargs
class.
Example:
raw_slots instance-attribute
¤
Slots passed to the component.
This is part of the Render API.
Unlike Component.slots
, this attribute is not typed and will remain as plain dict even if you define the Component.Slots
class.
Example:
registered_name instance-attribute
¤
If the component was rendered with the {% component %}
template tag, this will be the name under which the component was registered in the ComponentRegistry
.
Otherwise, this will be None
.
Example:
@register("my_component")
class MyComponent(Component):
template = "{{ name }}"
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.registered_name,
}
Will print my_component
in the template:
And None
when rendered in Python:
registry instance-attribute
¤
registry: ComponentRegistry
The ComponentRegistry
instance that was used to render the component.
request instance-attribute
¤
request: Optional[HttpRequest]
HTTPRequest object passed to this component.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
user_id = self.request.GET['user_id']
return {
'user_id': user_id,
}
Passing request
to a component:
In regular Django templates, you have to use RequestContext
to pass the HttpRequest
object to the template.
With Components, you can either use RequestContext
, or pass the request
object explicitly via Component.render()
and Component.render_to_response()
.
When a component is nested in another, the child component uses parent's request
object.
response_class class-attribute
¤
response_class: Type[HttpResponse] = HttpResponse
This attribute configures what class is used to generate response from Component.render_to_response()
.
The response class should accept a string as the first argument.
Defaults to django.http.HttpResponse
.
Example:
slots instance-attribute
¤
slots: Any
Slots passed to the component.
This is part of the Render API.
slots
has the same behavior as the slots
argument of Component.get_template_data()
:
- If you defined the
Component.Slots
class, then theslots
property will return an instance of that class. - Otherwise,
slots
will be a plain dict.
Example:
With Slots
class:
from django_components import Component, Slot, SlotInput
class Table(Component):
class Slots(NamedTuple):
header: SlotInput
footer: SlotInput
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert isinstance(self.slots.header, Slot)
assert isinstance(self.slots.footer, Slot)
rendered = Table.render(
slots={
"header": "MY_HEADER",
"footer": lambda ctx: "FOOTER: " + ctx.data["user_id"],
},
)
Without Slots
class:
template class-attribute
instance-attribute
¤
Inlined Django template (as a plain string) associated with this component.
Warning
Only one of template_file
, template
, get_template_name()
, or get_template()
must be defined.
Example:
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.django_html
.
Learn more about syntax highlighting.
template_file class-attribute
¤
Filepath to the Django template associated with this component.
The filepath must be either:
- Relative to the directory where the Component's Python file is defined.
- Relative to one of the component directories, as set by
COMPONENTS.dirs
orCOMPONENTS.app_dirs
(e.g.<root>/components/
). - Relative to the template directories, as set by Django's
TEMPLATES
setting (e.g.<root>/templates/
).
Warning
Only one of template_file
, get_template_name
, template
or get_template
must be defined.
Example:
Assuming this project layout:
Template name can be either relative to the python file (components/table/table.py
):
Or relative to one of the directories in COMPONENTS.dirs
or COMPONENTS.app_dirs
(components/
):
template_name class-attribute
¤
Alias for template_file
.
For historical reasons, django-components used template_name
to align with Django's TemplateView.
template_file
was introduced to align with js
/js_file
and css
/css_file
.
Setting and accessing this attribute is proxied to template_file
.
view instance-attribute
¤
view: ComponentView
Instance of ComponentView
available at component render time.
as_view classmethod
¤
as_view(**initkwargs: Any) -> ViewFn
Shortcut for calling Component.View.as_view
and passing component instance to it.
Read more on Component views and URLs.
get_context_data ¤
DEPRECATED: Use get_template_data()
instead. Will be removed in v2.
Use this method to define variables that will be available in the template.
Receives the args and kwargs as they were passed to the Component.
This method has access to the Render API.
Read more about Template variables.
Example:
class MyComponent(Component):
def get_context_data(self, name, *args, **kwargs):
return {
"name": name,
"id": self.id,
}
template = "Hello, {{ name }}!"
MyComponent.render(name="World")
Warning
get_context_data()
and get_template_data()
are mutually exclusive.
If both methods return non-empty dictionaries, an error will be raised.
get_css_data ¤
Use this method to define variables that will be available from within the component's CSS code.
This method has access to the Render API.
The data returned from this method will be serialized to string.
Read more about CSS variables.
Example:
class MyComponent(Component):
def get_css_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
}
css = '''
.my-class {
color: var(--color);
}
'''
MyComponent.render(color="red")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
:Context
used for rendering the component template.
Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the CSS code.
To do that, simply return the kwargs
dictionary itself from get_css_data()
:
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_css_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_css_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
}
You can also add typing to the data returned from get_css_data()
by defining the CssData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of CssData
.
If you return plain dictionary, the data will be validated against the CssData
class by instantiating it with the dictionary.
Example:
get_js_data ¤
Use this method to define variables that will be available from within the component's JavaScript code.
This method has access to the Render API.
The data returned from this method will be serialized to JSON.
Read more about JavaScript variables.
Example:
class MyComponent(Component):
def get_js_data(self, args, kwargs, slots, context):
return {
"name": kwargs["name"],
"id": self.id,
}
js = '''
$onLoad(({ name, id }) => {
console.log(name, id);
});
'''
MyComponent.render(name="World")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
:Context
used for rendering the component template.
Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the JavaScript code.
To do that, simply return the kwargs
dictionary itself from get_js_data()
:
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_js_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_js_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
"id": self.id,
}
You can also add typing to the data returned from get_js_data()
by defining the JsData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of JsData
.
If you return plain dictionary, the data will be validated against the JsData
class by instantiating it with the dictionary.
Example:
get_template ¤
DEPRECATED: Use instead Component.template_file
, Component.template
or Component.on_render()
. Will be removed in v1.
Same as Component.template
, but allows to dynamically resolve the template at render time.
The template can be either plain string or a Template
instance.
See Component.template
for more info and examples.
Warning
Only one of template
template_file
, get_template_name()
, or get_template()
must be defined.
Warning
The context is not fully populated at the point when this method is called.
If you need to access the context, either use Component.on_render_before()
or Component.on_render()
.
Parameters:
-
context
(Context
) –The Django template
Context
in which the component is rendered.
Returns:
get_template_data ¤
Use this method to define variables that will be available in the template.
This method has access to the Render API.
Read more about Template variables.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": kwargs["name"],
"id": self.id,
}
template = "Hello, {{ name }}!"
MyComponent.render(name="World")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
:Context
used for rendering the component template.
Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the template (similar to django-cotton).
To do that, simply return the kwargs
dictionary itself from get_template_data()
:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return kwargs
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_template_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_template_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
"id": self.id,
}
You can also add typing to the data returned from get_template_data()
by defining the TemplateData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of TemplateData
.
If you return plain dictionary, the data will be validated against the TemplateData
class by instantiating it with the dictionary.
Example:
class MyComponent(Component):
class TemplateData(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
"size": kwargs["size"],
}
# or
return MyComponent.TemplateData(
color=kwargs["color"],
size=kwargs["size"],
)
Warning
get_template_data()
and get_context_data()
are mutually exclusive.
If both methods return non-empty dictionaries, an error will be raised.
get_template_name ¤
DEPRECATED: Use instead Component.template_file
, Component.template
or Component.on_render()
. Will be removed in v1.
Same as Component.template_file
, but allows to dynamically resolve the template name at render time.
See Component.template_file
for more info and examples.
Warning
The context is not fully populated at the point when this method is called.
If you need to access the context, either use Component.on_render_before()
or Component.on_render()
.
Warning
Only one of template_file
, get_template_name()
, template
or get_template()
must be defined.
Parameters:
-
context
(Context
) –The Django template
Context
in which the component is rendered.
Returns:
inject ¤
Use this method to retrieve the data that was passed to a {% provide %}
tag with the corresponding key.
To retrieve the data, inject()
must be called inside a component that's inside the {% provide %}
tag.
You may also pass a default that will be used if the {% provide %}
tag with given key was NOT found.
This method is part of the Render API, and raises an error if called from outside the rendering execution.
Read more about Provide / Inject.
Example:
Given this template:
And given this definition of "my_comp" component:
from django_components import Component, register
@register("my_comp")
class MyComp(Component):
template = "hi {{ message }}!"
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("my_provide")
message = data.message
return {"message": message}
This renders into:
As the {{ message }}
is taken from the "my_provide" provider.
on_render ¤
on_render(context: Context, template: Optional[Template]) -> Union[SlotResult, OnRenderGenerator, None]
This method does the actual rendering.
Read more about this hook in Component hooks.
You can override this method to:
- Change what template gets rendered
- Modify the context
- Modify the rendered output after it has been rendered
- Handle errors
The default implementation renders the component's Template with the given Context.
class MyTable(Component):
def on_render(self, context, template):
if template is None:
return None
else:
return template.render(context)
The template
argument is None
if the component has no template.
Modifying rendered template
To change what gets rendered, you can:
- Render a different template
- Render a component
- Return a different string or SafeString
Post-processing rendered template
To access the final output, you can yield
the result instead of returning it.
This will return a tuple of (rendered HTML, error). The error is None
if the rendering succeeded.
class MyTable(Component):
def on_render(self, context, template):
html, error = yield template.render(context)
if error is None:
# The rendering succeeded
return html
else:
# The rendering failed
print(f"Error: {error}")
At this point you can do 3 things:
-
Return a new HTML
The new HTML will be used as the final output.
If the original template raised an error, it will be ignored.
-
Raise a new exception
The new exception is what will bubble up from the component.
The original HTML and original error will be ignored.
-
Return nothing (or
None
) to handle the result as usualIf you don't raise an exception, and neither return a new HTML, then original HTML / error will be used:
- If rendering succeeded, the original HTML will be used as the final output.
- If rendering failed, the original error will be propagated.
on_render_after ¤
on_render_after(context: Context, template: Optional[Template], result: Optional[str], error: Optional[Exception]) -> Optional[SlotResult]
Hook that runs when the component was fully rendered, including all its children.
It receives the same arguments as on_render_before()
, plus the outcome of the rendering:
result
: The rendered output of the component.None
if the rendering failed.error
: The error that occurred during the rendering, orNone
if the rendering succeeded.
on_render_after()
behaves the same way as the second part of on_render()
(after the yield
).
class MyTable(Component):
def on_render_after(self, context, template, result, error):
if error is None:
# The rendering succeeded
return result
else:
# The rendering failed
print(f"Error: {error}")
Same as on_render()
, you can return a new HTML, raise a new exception, or return nothing:
-
Return a new HTML
The new HTML will be used as the final output.
If the original template raised an error, it will be ignored.
-
Raise a new exception
The new exception is what will bubble up from the component.
The original HTML and original error will be ignored.
-
Return nothing (or
None
) to handle the result as usualIf you don't raise an exception, and neither return a new HTML, then original HTML / error will be used:
- If rendering succeeded, the original HTML will be used as the final output.
- If rendering failed, the original error will be propagated.
on_render_before ¤
on_render_before(context: Context, template: Optional[Template]) -> None
Runs just before the component's template is rendered.
It is called for every component, including nested ones, as part of the component render lifecycle.
Parameters:
-
context
(Context
) –The Django Context that will be used to render the component's template.
-
template
(Optional[Template]
) –The Django Template instance that will be rendered, or
None
if no template.
Returns:
-
None
–None. This hook is for side effects only.
Example:
You can use this hook to access the context or the template:
from django.template import Context, Template
from django_components import Component
class MyTable(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
# Insert value into the Context
context["from_on_before"] = ":)"
assert isinstance(template, Template)
Warning
If you want to pass data to the template, prefer using get_template_data()
instead of this hook.
Warning
Do NOT modify the template in this hook. The template is reused across renders.
Since this hook is called for every component, this means that the template would be modified every time a component is rendered.
render classmethod
¤
render(
context: Optional[Union[Dict[str, Any], Context]] = None,
args: Optional[Any] = None,
kwargs: Optional[Any] = None,
slots: Optional[Any] = None,
deps_strategy: DependenciesStrategy = "document",
type: Optional[DependenciesStrategy] = None,
render_dependencies: bool = True,
request: Optional[HttpRequest] = None,
outer_context: Optional[Context] = None,
registry: Optional[ComponentRegistry] = None,
registered_name: Optional[str] = None,
node: Optional[ComponentNode] = None,
) -> str
Render the component into a string. This is the equivalent of calling the {% component %}
tag.
Button.render(
args=["John"],
kwargs={
"surname": "Doe",
"age": 30,
},
slots={
"footer": "i AM A SLOT",
},
)
Inputs:
-
args
- Optional. A list of positional args for the component. This is the same as calling the component as: -
kwargs
- Optional. A dictionary of keyword arguments for the component. This is the same as calling the component as: -
slots
- Optional. A dictionary of slot fills. This is the same as passing{% fill %}
tags to the component.Dictionary keys are the slot names. Dictionary values are the slot fills.
Slot fills can be strings, render functions, or
Slot
instances: -
context
- Optional. Plain dictionary or Django's Context. The context within which the component is rendered.When a component is rendered within a template with the
{% component %}
tag, this will be set to the Context instance that is used for rendering the template.When you call
Component.render()
directly from Python, you can ignore this input most of the time. Instead useargs
,kwargs
, andslots
to pass data to the component.You can pass
RequestContext
to thecontext
argument, so that the component will gain access to the request object and will use context processors. Read more on Working with HTTP requests.For advanced use cases, you can use
context
argument to "pre-render" the component in Python, and then pass the rendered output as plain string to the template. With this, the inner component is rendered as if it was within the template with{% component %}
.class Button(Component): def render(self, context, template): # Pass `context` to Icon component so it is rendered # as if nested within Button. icon = Icon.render( context=context, args=["icon-name"], deps_strategy="ignore", ) # Update context with icon with context.update({"icon": icon}): return template.render(context)
Whether the variables defined in
context
are available to the template depends on the context behavior mode:-
In
"django"
context behavior mode, the template will have access to the keys of this context. -
In
"isolated"
context behavior mode, the template will NOT have access to this context, and data MUST be passed via component's args and kwargs.
-
-
deps_strategy
- Optional. Configure how to handle JS and CSS dependencies. Read more about Dependencies rendering.There are six strategies:
"document"
(default)- Smartly inserts JS / CSS into placeholders or into
<head>
and<body>
tags. - Inserts extra script to allow
fragment
types to work. - Assumes the HTML will be rendered in a JS-enabled browser.
- Smartly inserts JS / CSS into placeholders or into
"fragment"
- A lightweight HTML fragment to be inserted into a document with AJAX.
- No JS / CSS included.
"simple"
- Smartly insert JS / CSS into placeholders or into
<head>
and<body>
tags. - No extra script loaded.
- Smartly insert JS / CSS into placeholders or into
"prepend"
- Insert JS / CSS before the rendered HTML.
- No extra script loaded.
"append"
- Insert JS / CSS after the rendered HTML.
- No extra script loaded.
"ignore"
- HTML is left as-is. You can still process it with a different strategy later with
render_dependencies()
. - Used for inserting rendered HTML into other components.
- HTML is left as-is. You can still process it with a different strategy later with
-
request
- Optional. HTTPRequest object. Pass a request object directly to the component to apply context processors.Read more about Working with HTTP requests.
Type hints:
Component.render()
is NOT typed. To add type hints, you can wrap the inputs in component's Args
, Kwargs
, and Slots
classes.
Read more on Typing and validation.
from typing import NamedTuple, Optional
from django_components import Component, Slot, SlotInput
# Define the component with the types
class Button(Component):
class Args(NamedTuple):
name: str
class Kwargs(NamedTuple):
surname: str
age: int
class Slots(NamedTuple):
my_slot: Optional[SlotInput] = None
footer: SlotInput
# Add type hints to the render call
Button.render(
args=Button.Args(
name="John",
),
kwargs=Button.Kwargs(
surname="Doe",
age=30,
),
slots=Button.Slots(
footer=Slot(lambda ctx: "Click me!"),
),
)
render_to_response classmethod
¤
render_to_response(
context: Optional[Union[Dict[str, Any], Context]] = None,
args: Optional[Any] = None,
kwargs: Optional[Any] = None,
slots: Optional[Any] = None,
deps_strategy: DependenciesStrategy = "document",
type: Optional[DependenciesStrategy] = None,
render_dependencies: bool = True,
request: Optional[HttpRequest] = None,
outer_context: Optional[Context] = None,
registry: Optional[ComponentRegistry] = None,
registered_name: Optional[str] = None,
node: Optional[ComponentNode] = None,
**response_kwargs: Any
) -> HttpResponse
Render the component and wrap the content in an HTTP response class.
render_to_response()
takes the same inputs as Component.render()
. See that method for more information.
After the component is rendered, the HTTP response class is instantiated with the rendered content.
Any additional kwargs are passed to the response class.
Example:
Button.render_to_response(
args=["John"],
kwargs={
"surname": "Doe",
"age": 30,
},
slots={
"footer": "i AM A SLOT",
},
# HttpResponse kwargs
status=201,
headers={...},
)
# HttpResponse(content=..., status=201, headers=...)
Custom response class:
You can set a custom response class on the component via Component.response_class
. Defaults to django.http.HttpResponse
.
ComponentCache ¤
ComponentCache(component: Component)
Bases: django_components.extension.ExtensionComponentConfig
The interface for Component.Cache
.
The fields of this class are used to configure the component caching.
Read more about Component caching.
Example:
from django_components import Component
class MyComponent(Component):
class Cache:
enabled = True
ttl = 60 * 60 * 24 # 1 day
cache_name = "my_cache"
Methods:
-
get_cache
– -
get_cache_key
– -
get_entry
– -
hash
– -
hash_slots
– -
set_entry
–
Attributes:
-
cache_name
(Optional[str]
) – -
component
(Component
) – -
component_class
(Type[Component]
) – -
component_cls
(Type[Component]
) – -
enabled
(bool
) – -
include_slots
(bool
) – -
ttl
(Optional[int]
) –
cache_name class-attribute
instance-attribute
¤
The name of the cache to use. If None
, the default cache will be used.
component instance-attribute
¤
component: Component = component
enabled class-attribute
instance-attribute
¤
enabled: bool = False
Whether this Component should be cached. Defaults to False
.
include_slots class-attribute
instance-attribute
¤
include_slots: bool = False
Whether the slots should be hashed into the cache key.
If enabled, the following two cases will be treated as different entries:
{% component "mycomponent" name="foo" %}
FILL ONE
{% endcomponent %}
{% component "mycomponent" name="foo" %}
FILL TWO
{% endcomponent %}
Warning
Passing slots as functions to cached components with include_slots=True
will raise an error.
Warning
Slot caching DOES NOT account for context variables within the {% fill %}
tag.
For example, the following two cases will be treated as the same entry:
{% with my_var="foo" %}
{% component "mycomponent" name="foo" %}
{{ my_var }}
{% endcomponent %}
{% endwith %}
{% with my_var="bar" %}
{% component "mycomponent" name="bar" %}
{{ my_var }}
{% endcomponent %}
{% endwith %}
Currently it's impossible to capture used variables. This will be addressed in v2. Read more about it in https://github.com/django-components/django-components/issues/1164.
ttl class-attribute
instance-attribute
¤
The time-to-live (TTL) in seconds, i.e. for how long should an entry be valid in the cache.
- If
> 0
, the entries will be cached for the given number of seconds. - If
-1
, the entries will be cached indefinitely. - If
0
, the entries won't be cached. - If
None
, the default TTL will be used.
hash ¤
Defines how the input (both args and kwargs) is hashed into a cache key.
By default, hash()
serializes the input into a string. As such, the default implementation might NOT be suitable if you need to hash complex objects.
ComponentDebugHighlight ¤
ComponentDebugHighlight(component: Component)
Bases: django_components.extension.ExtensionComponentConfig
The interface for Component.DebugHighlight
.
The fields of this class are used to configure the component debug highlighting for this component and its direct slots.
Read more about Component debug highlighting.
Example:
from django_components import Component
class MyComponent(Component):
class DebugHighlight:
highlight_components = True
highlight_slots = True
To highlight ALL components and slots, set extension defaults in your settings:
from django_components import ComponentsSettings
COMPONENTS = ComponentsSettings(
extensions_defaults={
"debug_highlight": {
"highlight_components": True,
"highlight_slots": True,
},
},
)
Attributes:
-
component
(Component
) – -
component_class
(Type[Component]
) – -
component_cls
(Type[Component]
) – -
highlight_components
– -
highlight_slots
–
component instance-attribute
¤
component: Component = component
highlight_components class-attribute
instance-attribute
¤
Whether to highlight this component in the rendered output.
highlight_slots class-attribute
instance-attribute
¤
Whether to highlight slots of this component in the rendered output.
ComponentDefaults ¤
ComponentDefaults(component: Component)
Bases: django_components.extension.ExtensionComponentConfig
The interface for Component.Defaults
.
The fields of this class are used to set default values for the component's kwargs.
Read more about Component defaults.
Example:
from django_components import Component, Default
class MyComponent(Component):
class Defaults:
position = "left"
selected_items = Default(lambda: [1, 2, 3])
Attributes:
-
component
(Component
) – -
component_class
(Type[Component]
) – -
component_cls
(Type[Component]
) –
component instance-attribute
¤
component: Component = component
ComponentExtension ¤
Bases: object
Base class for all extensions.
Read more on Extensions.
Example:
class ExampleExtension(ComponentExtension):
name = "example"
# Component-level behavior and settings. User will be able to override
# the attributes and methods defined here on the component classes.
class ComponentConfig(ComponentExtension.ComponentConfig):
foo = "1"
bar = "2"
def baz(cls):
return "3"
# URLs
urls = [
URLRoute(path="dummy-view/", handler=dummy_view, name="dummy"),
URLRoute(path="dummy-view-2/<int:id>/<str:name>/", handler=dummy_view_2, name="dummy-2"),
]
# Commands
commands = [
HelloWorldCommand,
]
# Hooks
def on_component_class_created(self, ctx: OnComponentClassCreatedContext) -> None:
print(ctx.component_cls.__name__)
def on_component_class_deleted(self, ctx: OnComponentClassDeletedContext) -> None:
print(ctx.component_cls.__name__)
Which users then can override on a per-component basis. E.g.:
Methods:
-
on_component_class_created
– -
on_component_class_deleted
– -
on_component_data
– -
on_component_input
– -
on_component_registered
– -
on_component_rendered
– -
on_component_unregistered
– -
on_registry_created
– -
on_registry_deleted
– -
on_slot_rendered
–
Attributes:
-
ComponentConfig
(Type[ExtensionComponentConfig]
) – -
class_name
(str
) – -
commands
(List[Type[ComponentCommand]]
) – -
name
(str
) – -
urls
(List[URLRoute]
) –
ComponentConfig class-attribute
¤
ComponentConfig: Type[ExtensionComponentConfig] = ExtensionComponentConfig
Base class that the "component-level" extension config nested within a Component
class will inherit from.
This is where you can define new methods and attributes that will be available to the component instance.
Background:
The extension may add new features to the Component
class by allowing users to define and access a nested class in the Component
class. E.g.:
class MyComp(Component):
class MyExtension:
...
def get_template_data(self, args, kwargs, slots, context):
return {
"my_extension": self.my_extension.do_something(),
}
When rendering a component, the nested extension class will be set as a subclass of ComponentConfig
. So it will be same as if the user had directly inherited from extension's ComponentConfig
. E.g.:
This setting decides what the extension class will inherit from.
class_name class-attribute
¤
class_name: str
Name of the extension class.
By default, this is set automatically at class creation. The class name is the same as the name
attribute, but with snake_case converted to PascalCase.
So if the extension name is "my_extension"
, then the extension class name will be "MyExtension"
.
To customize the class name, you can manually set the class_name
attribute.
The class name must be a valid Python identifier.
Example:
This will make the extension class name "MyCustomExtension"
.
commands class-attribute
¤
commands: List[Type[ComponentCommand]] = []
List of commands that can be run by the extension.
These commands will be available to the user as components ext run <extension> <command>
.
Commands are defined as subclasses of ComponentCommand
.
Example:
This example defines an extension with a command that prints "Hello world". To run the command, the user would run components ext run hello_world hello
.
from django_components import ComponentCommand, ComponentExtension, CommandArg, CommandArgGroup
class HelloWorldCommand(ComponentCommand):
name = "hello"
help = "Hello world command."
# Allow to pass flags `--foo`, `--bar` and `--baz`.
# Argument parsing is managed by `argparse`.
arguments = [
CommandArg(
name_or_flags="--foo",
help="Foo description.",
),
# When printing the command help message, `bar` and `baz`
# will be grouped under "group bar".
CommandArgGroup(
title="group bar",
description="Group description.",
arguments=[
CommandArg(
name_or_flags="--bar",
help="Bar description.",
),
CommandArg(
name_or_flags="--baz",
help="Baz description.",
),
],
),
]
# Callback that receives the parsed arguments and options.
def handle(self, *args, **kwargs):
print(f"HelloWorldCommand.handle: args={args}, kwargs={kwargs}")
# Associate the command with the extension
class HelloWorldExtension(ComponentExtension):
name = "hello_world"
commands = [
HelloWorldCommand,
]
name class-attribute
¤
name: str
Name of the extension.
Name must be lowercase, and must be a valid Python identifier (e.g. "my_extension"
).
The extension may add new features to the Component
class by allowing users to define and access a nested class in the Component
class.
The extension name determines the name of the nested class in the Component
class, and the attribute under which the extension will be accessible.
E.g. if the extension name is "my_extension"
, then the nested class in the Component
class will be MyExtension
, and the extension will be accessible as MyComp.my_extension
.
class MyComp(Component):
class MyExtension:
...
def get_template_data(self, args, kwargs, slots, context):
return {
"my_extension": self.my_extension.do_something(),
}
Info
The extension class name can be customized by setting the class_name
attribute.
on_component_class_created ¤
on_component_class_created(ctx: OnComponentClassCreatedContext) -> None
on_component_class_deleted ¤
on_component_class_deleted(ctx: OnComponentClassDeletedContext) -> None
Called when a Component
class is being deleted.
This hook is called before the Component
class is deleted from memory.
Use this hook to perform any cleanup related to the Component
class.
Example:
from django_components import ComponentExtension, OnComponentClassDeletedContext
class MyExtension(ComponentExtension):
def on_component_class_deleted(self, ctx: OnComponentClassDeletedContext) -> None:
# Remove Component class from the extension's cache on deletion
self.cache.pop(ctx.component_cls, None)
on_component_data ¤
on_component_data(ctx: OnComponentDataContext) -> None
Called when a Component
was triggered to render, after a component's context and data methods have been processed.
This hook is called after Component.get_template_data()
, Component.get_js_data()
and Component.get_css_data()
.
This hook runs after on_component_input
.
Use this hook to modify or validate the component's data before rendering.
Example:
on_component_input ¤
on_component_input(ctx: OnComponentInputContext) -> Optional[str]
Called when a Component
was triggered to render, but before a component's context and data methods are invoked.
Use this hook to modify or validate component inputs before they're processed.
This is the first hook that is called when rendering a component. As such this hook is called before Component.get_template_data()
, Component.get_js_data()
, and Component.get_css_data()
methods, and the on_component_data
hook.
This hook also allows to skip the rendering of a component altogether. If the hook returns a non-null value, this value will be used instead of rendering the component.
You can use this to implement a caching mechanism for components, or define components that will be rendered conditionally.
Example:
from django_components import ComponentExtension, OnComponentInputContext
class MyExtension(ComponentExtension):
def on_component_input(self, ctx: OnComponentInputContext) -> None:
# Add extra kwarg to all components when they are rendered
ctx.kwargs["my_input"] = "my_value"
Warning
In this hook, the components' inputs are still mutable.
As such, if a component defines Args
, Kwargs
, Slots
types, these types are NOT yet instantiated.
Instead, component fields like Component.args
, Component.kwargs
, Component.slots
are plain list
/ dict
objects.
on_component_registered ¤
on_component_registered(ctx: OnComponentRegisteredContext) -> None
Called when a Component
class is registered with a ComponentRegistry
.
This hook is called after a Component
class is successfully registered.
Example:
on_component_rendered ¤
Called when a Component
was rendered, including all its child components.
Use this hook to access or post-process the component's rendered output.
This hook works similarly to Component.on_render_after()
:
-
To modify the output, return a new string from this hook. The original output or error will be ignored.
-
To cause this component to return a new error, raise that error. The original output and error will be ignored.
-
If you neither raise nor return string, the original output or error will be used.
Examples:
Change the final output of a component:
from django_components import ComponentExtension, OnComponentRenderedContext
class MyExtension(ComponentExtension):
def on_component_rendered(self, ctx: OnComponentRenderedContext) -> Optional[str]:
# Append a comment to the component's rendered output
return ctx.result + "<!-- MyExtension comment -->"
Cause the component to raise a new exception:
from django_components import ComponentExtension, OnComponentRenderedContext
class MyExtension(ComponentExtension):
def on_component_rendered(self, ctx: OnComponentRenderedContext) -> Optional[str]:
# Raise a new exception
raise Exception("Error message")
Return nothing (or None
) to handle the result as usual:
from django_components import ComponentExtension, OnComponentRenderedContext
class MyExtension(ComponentExtension):
def on_component_rendered(self, ctx: OnComponentRenderedContext) -> Optional[str]:
if ctx.error is not None:
# The component raised an exception
print(f"Error: {ctx.error}")
else:
# The component rendered successfully
print(f"Result: {ctx.result}")
on_component_unregistered ¤
on_component_unregistered(ctx: OnComponentUnregisteredContext) -> None
Called when a Component
class is unregistered from a ComponentRegistry
.
This hook is called after a Component
class is removed from the registry.
Example:
on_registry_created ¤
on_registry_created(ctx: OnRegistryCreatedContext) -> None
Called when a new ComponentRegistry
is created.
This hook is called after a new ComponentRegistry
instance is initialized.
Use this hook to perform any initialization needed for the registry.
Example:
on_registry_deleted ¤
on_registry_deleted(ctx: OnRegistryDeletedContext) -> None
Called when a ComponentRegistry
is being deleted.
This hook is called before a ComponentRegistry
instance is deleted.
Use this hook to perform any cleanup related to the registry.
Example:
on_slot_rendered ¤
Called when a {% slot %}
tag was rendered.
Use this hook to access or post-process the slot's rendered output.
To modify the output, return a new string from this hook.
Example:
from django_components import ComponentExtension, OnSlotRenderedContext
class MyExtension(ComponentExtension):
def on_slot_rendered(self, ctx: OnSlotRenderedContext) -> Optional[str]:
# Append a comment to the slot's rendered output
return ctx.result + "<!-- MyExtension comment -->"
Access slot metadata:
You can access the {% slot %}
tag node (SlotNode
) and its metadata using ctx.slot_node
.
For example, to find the Component
class to which belongs the template where the {% slot %}
tag is defined, you can use ctx.slot_node.template_component
:
from django_components import ComponentExtension, OnSlotRenderedContext
class MyExtension(ComponentExtension):
def on_slot_rendered(self, ctx: OnSlotRenderedContext) -> Optional[str]:
# Access slot metadata
slot_node = ctx.slot_node
slot_owner = slot_node.template_component
print(f"Slot owner: {slot_owner}")
ComponentFileEntry ¤
Bases: tuple
Result returned by get_component_files()
.
Attributes:
ComponentInput dataclass
¤
ComponentInput(
context: Context,
args: List,
kwargs: Dict,
slots: Dict[SlotName, Slot],
deps_strategy: DependenciesStrategy,
type: DependenciesStrategy,
render_dependencies: bool,
)
Bases: object
Deprecated. Will be removed in v1.
Object holding the inputs that were passed to Component.render()
or the {% component %}
template tag.
This object is available only during render under Component.input
.
Read more about the Render API.
Attributes:
-
args
(List
) – -
context
(Context
) – -
deps_strategy
(DependenciesStrategy
) – -
kwargs
(Dict
) – -
render_dependencies
(bool
) – -
slots
(Dict[SlotName, Slot]
) – -
type
(DependenciesStrategy
) –
deps_strategy instance-attribute
¤
deps_strategy: DependenciesStrategy
Dependencies strategy passed to Component.render()
render_dependencies instance-attribute
¤
render_dependencies: bool
Deprecated. Will be removed in v1. Use deps_strategy="ignore"
instead.
slots instance-attribute
¤
Slots (as dict) passed to Component.render()
type instance-attribute
¤
type: DependenciesStrategy
Deprecated. Will be removed in v1. Use deps_strategy
instead.
ComponentMediaInput ¤
Bases: typing.Protocol
Defines JS and CSS media files associated with a Component
.
class MyTable(Component):
class Media:
js = [
"path/to/script.js",
"https://unpkg.com/alpinejs@3.14.7/dist/cdn.min.js", # AlpineJS
]
css = {
"all": [
"path/to/style.css",
"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", # TailwindCSS
],
"print": ["path/to/style2.css"],
}
Attributes:
-
css
(Optional[Union[ComponentMediaInputPath, List[ComponentMediaInputPath], Dict[str, ComponentMediaInputPath], Dict[str, List[ComponentMediaInputPath]]]]
) – -
extend
(Union[bool, List[Type[Component]]]
) – -
js
(Optional[Union[ComponentMediaInputPath, List[ComponentMediaInputPath]]]
) –
css class-attribute
instance-attribute
¤
css: Optional[
Union[
ComponentMediaInputPath, List[ComponentMediaInputPath], Dict[str, ComponentMediaInputPath], Dict[str, List[ComponentMediaInputPath]]
]
] = None
CSS files associated with a Component
.
-
If a string, it's assumed to be a path to a CSS file.
-
If a list, each entry is assumed to be a path to a CSS file.
-
If a dict, the keys are media types (e.g. "all", "print", "screen", etc.), and the values are either:
- A string, assumed to be a path to a CSS file.
- A list, each entry is assumed to be a path to a CSS file.
Each entry can be a string, bytes, SafeString, PathLike, or a callable that returns one of the former (see ComponentMediaInputPath
).
Examples:
extend class-attribute
instance-attribute
¤
Configures whether the component should inherit the media files from the parent component.
- If
True
, the component inherits the media files from the parent component. - If
False
, the component does not inherit the media files from the parent component. - If a list of components classes, the component inherits the media files ONLY from these specified components.
Read more in Media inheritance section.
Example:
Disable media inheritance:
class ParentComponent(Component):
class Media:
js = ["parent.js"]
class MyComponent(ParentComponent):
class Media:
extend = False # Don't inherit parent media
js = ["script.js"]
print(MyComponent.media._js) # ["script.js"]
Specify which components to inherit from. In this case, the media files are inherited ONLY from the specified components, and NOT from the original parent components:
class ParentComponent(Component):
class Media:
js = ["parent.js"]
class MyComponent(ParentComponent):
class Media:
# Only inherit from these, ignoring the files from the parent
extend = [OtherComponent1, OtherComponent2]
js = ["script.js"]
print(MyComponent.media._js) # ["script.js", "other1.js", "other2.js"]
js class-attribute
instance-attribute
¤
js: Optional[Union[ComponentMediaInputPath, List[ComponentMediaInputPath]]] = None
JS files associated with a Component
.
-
If a string, it's assumed to be a path to a JS file.
-
If a list, each entry is assumed to be a path to a JS file.
Each entry can be a string, bytes, SafeString, PathLike, or a callable that returns one of the former (see ComponentMediaInputPath
).
Examples:
ComponentMediaInputPath module-attribute
¤
ComponentMediaInputPath = Union[str, bytes, SafeData, Path, PathLike, Callable[[], Union[str, bytes, SafeData, Path, PathLike]]]
A type representing an entry in Media.js or Media.css.
If an entry is a SafeString (or has __html__
method), then entry is assumed to be a formatted HTML tag. Otherwise, it's assumed to be a path to a file.
Example:
ComponentNode ¤
ComponentNode(
name: str,
registry: ComponentRegistry,
params: List[TagAttr],
flags: Optional[Dict[str, bool]] = None,
nodelist: Optional[NodeList] = None,
node_id: Optional[str] = None,
contents: Optional[str] = None,
template_name: Optional[str] = None,
template_component: Optional[Type[Component]] = None,
)
Bases: django_components.node.BaseNode
Renders one of the components that was previously registered with @register()
decorator.
The {% component %}
tag takes:
- Component's registered name as the first positional argument,
- Followed by any number of positional and keyword arguments.
The component name must be a string literal.
Inserting slot fills¤
If the component defined any slots, you can "fill" these slots by placing the {% fill %}
tags within the {% component %}
tag:
{% component "my_table" rows=rows headers=headers %}
{% fill "pagination" %}
< 1 | 2 | 3 >
{% endfill %}
{% endcomponent %}
You can even nest {% fill %}
tags within {% if %}
, {% for %}
and other tags:
{% component "my_table" rows=rows headers=headers %}
{% if rows %}
{% fill "pagination" %}
< 1 | 2 | 3 >
{% endfill %}
{% endif %}
{% endcomponent %}
Isolating components¤
By default, components behave similarly to Django's {% include %}
, and the template inside the component has access to the variables defined in the outer template.
You can selectively isolate a component, using the only
flag, so that the inner template can access only the data that was explicitly passed to it:
Alternatively, you can set all components to be isolated by default, by setting context_behavior
to "isolated"
in your settings:
Omitting the component keyword¤
If you would like to omit the component
keyword, and simply refer to your components by their registered names:
You can do so by setting the "shorthand" Tag formatter in the settings:
Methods:
-
parse
– -
register
– -
render
– -
unregister
–
Attributes:
-
active_flags
(List[str]
) – -
allowed_flags
– -
contents
(Optional[str]
) – -
end_tag
– -
flags
(Dict[str, bool]
) – -
name
– -
node_id
(str
) – -
nodelist
(NodeList
) – -
params
(List[TagAttr]
) – -
registry
– -
tag
– -
template_component
(Optional[Type[Component]]
) – -
template_name
(Optional[str]
) –
active_flags property
¤
Flags that were set for this specific instance as a list of strings.
E.g. the following tag:
Will have the following flags:
contents instance-attribute
¤
The contents of the tag.
This is the text between the opening and closing tags, e.g.
The contents
will be "<div> ... </div>"
.
flags instance-attribute
¤
Dictionary of all allowed_flags
that were set on the tag.
Flags that were set are True
, and the rest are False
.
E.g. the following tag:
Has 2 flags, default
and required
, but only default
was set.
The flags
dictionary will be:
You can check if a flag is set by doing:
node_id instance-attribute
¤
node_id: str = node_id or gen_id()
The unique ID of the node.
Extensions can use this ID to store additional information.
nodelist instance-attribute
¤
The nodelist of the tag.
This is the text between the opening and closing tags, e.g.
The nodelist
will contain the <div> ... </div>
part.
Unlike contents
, the nodelist
contains the actual Nodes, not just the text.
params instance-attribute
¤
params: List[TagAttr] = params
The parameters to the tag in the template.
A single param represents an arg or kwarg of the template tag.
E.g. the following tag:
Has 3 params:
- Posiitonal arg
"my_comp"
- Keyword arg
key=val
- Keyword arg
key2='val2 two'
template_component instance-attribute
¤
template_name instance-attribute
¤
The name of the Template
that contains this node.
The template name is set by Django's template loaders.
For example, the filesystem template loader will set this to the absolute path of the template file.
parse classmethod
¤
parse(parser: Parser, token: Token, registry: ComponentRegistry, name: str, start_tag: str, end_tag: str) -> ComponentNode
register classmethod
¤
A convenience method for registering the tag with the given library.
Allows you to then use the node in templates like so:
unregister classmethod
¤
Unregisters the node from the given library.
ComponentRegistry ¤
ComponentRegistry(
library: Optional[Library] = None, settings: Optional[Union[RegistrySettings, Callable[[ComponentRegistry], RegistrySettings]]] = None
)
Bases: object
Manages components and makes them available in the template, by default as {% component %}
tags.
To enable a component to be used in a template, the component must be registered with a component registry.
When you register a component to a registry, behind the scenes the registry automatically adds the component's template tag (e.g. {% component %}
to the Library
. And the opposite happens when you unregister a component - the tag is removed.
Parameters:
-
library
(Library
, default:None
) –Django
Library
associated with this registry. If omitted, the default Library instance from django_components is used. -
settings
(Union[RegistrySettings, Callable[[ComponentRegistry], RegistrySettings]]
, default:None
) –Configure how the components registered with this registry will behave when rendered. See
RegistrySettings
. Can be either a static value or a callable that returns the settings. If omitted, the settings fromCOMPONENTS
are used.
Notes:
- The default registry is available as
django_components.registry
. - The default registry is used when registering components with
@register
decorator.
Example:
# Use with default Library
registry = ComponentRegistry()
# Or a custom one
my_lib = Library()
registry = ComponentRegistry(library=my_lib)
# Usage
registry.register("button", ButtonComponent)
registry.register("card", CardComponent)
registry.all()
registry.clear()
registry.get("button")
registry.has("button")
Using registry to share components¤
You can use component registry for isolating or "packaging" components:
-
Create new instance of
ComponentRegistry
and Library: -
Register components to the registry:
-
In your target project, load the Library associated with the registry:
-
Use the registered components in your templates:
Methods:
Attributes:
settings property
¤
Registry settings configured for this registry.
all ¤
clear ¤
Clears the registry, unregistering all components.
Example:
get ¤
Retrieve a Component
class registered under the given name.
Parameters:
-
name
(str
) –The name under which the component was registered. Required.
Returns:
Raises:
NotRegistered
if the given name is not registered.
Example:
has ¤
register ¤
Register a Component
class with this registry under the given name.
A component MUST be registered before it can be used in a template such as:
Parameters:
-
name
(str
) –The name under which the component will be registered. Required.
-
component
(Type[Component]
) –The component class to register. Required.
Raises:
AlreadyRegistered
if a different component was already registered under the same name.
Example:
unregister ¤
unregister(name: str) -> None
Unregister the Component
class that was registered under the given name.
Once a component is unregistered, it is no longer available in the templates.
Parameters:
-
name
(str
) –The name under which the component is registered. Required.
Raises:
NotRegistered
if the given name is not registered.
Example:
ComponentVars ¤
Bases: tuple
Type for the variables available inside the component templates.
All variables here are scoped under component_vars.
, so e.g. attribute kwargs
on this class is accessible inside the template as:
Attributes:
args instance-attribute
¤
args: Any
The args
argument as passed to Component.get_template_data()
.
This is the same Component.args
that's available on the component instance.
If you defined the Component.Args
class, then the args
property will return an instance of that class.
Otherwise, args
will be a plain list.
Example:
With Args
class:
from django_components import Component, register
@register("table")
class Table(Component):
class Args(NamedTuple):
page: int
per_page: int
template = '''
<div>
<h1>Table</h1>
<p>Page: {{ component_vars.args.page }}</p>
<p>Per page: {{ component_vars.args.per_page }}</p>
</div>
'''
Without Args
class:
is_filled instance-attribute
¤
Deprecated. Will be removed in v1. Use component_vars.slots
instead. Note that component_vars.slots
no longer escapes the slot names.
Dictonary describing which component slots are filled (True
) or are not (False
).
New in version 0.70
Use as {{ component_vars.is_filled }}
Example:
{# Render wrapping HTML only if the slot is defined #}
{% if component_vars.is_filled.my_slot %}
<div class="slot-wrapper">
{% slot "my_slot" / %}
</div>
{% endif %}
This is equivalent to checking if a given key is among the slot fills:
kwargs instance-attribute
¤
kwargs: Any
The kwargs
argument as passed to Component.get_template_data()
.
This is the same Component.kwargs
that's available on the component instance.
If you defined the Component.Kwargs
class, then the kwargs
property will return an instance of that class.
Otherwise, kwargs
will be a plain dict.
Example:
With Kwargs
class:
from django_components import Component, register
@register("table")
class Table(Component):
class Kwargs(NamedTuple):
page: int
per_page: int
template = '''
<div>
<h1>Table</h1>
<p>Page: {{ component_vars.kwargs.page }}</p>
<p>Per page: {{ component_vars.kwargs.per_page }}</p>
</div>
'''
Without Kwargs
class:
slots instance-attribute
¤
slots: Any
The slots
argument as passed to Component.get_template_data()
.
This is the same Component.slots
that's available on the component instance.
If you defined the Component.Slots
class, then the slots
property will return an instance of that class.
Otherwise, slots
will be a plain dict.
Example:
With Slots
class:
from django_components import Component, SlotInput, register
@register("table")
class Table(Component):
class Slots(NamedTuple):
footer: SlotInput
template = '''
<div>
{% component "pagination" %}
{% fill "footer" body=component_vars.slots.footer / %}
{% endcomponent %}
</div>
'''
Without Slots
class:
ComponentView ¤
Bases: django_components.extension.ExtensionComponentConfig
, django.views.generic.base.View
The interface for Component.View
.
The fields of this class are used to configure the component views and URLs.
This class is a subclass of django.views.View
. The Component
class is available via self.component_cls
.
Override the methods of this class to define the behavior of the component.
Read more about Component views and URLs.
Example:
class MyComponent(Component):
class View:
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
return HttpResponse("Hello, world!")
Component URL:
If the public
attribute is set to True
, the component will have its own URL that will point to the Component's View.
from django_components import Component
class MyComponent(Component):
class View:
public = True
def get(self, request, *args, **kwargs):
return HttpResponse("Hello, world!")
Will create a URL route like /components/ext/view/components/a1b2c3/
.
To get the URL for the component, use get_component_url()
:
Methods:
Attributes:
-
component
– -
component_class
(Type[Component]
) – -
component_cls
– -
public
(bool
) – -
url
(str
) –
component class-attribute
instance-attribute
¤
component = cast('Component', None)
DEPRECATED: Will be removed in v1.0. Use component_cls
instead.
This is a dummy instance created solely for the View methods.
It is the same as if you instantiated the component class directly:
component_cls class-attribute
instance-attribute
¤
The parent component class.
Example:
public class-attribute
¤
public: bool = False
Whether the component should be available via a URL.
Example:
Will create a URL route like /components/ext/view/components/a1b2c3/
.
To get the URL for the component, use get_component_url()
:
url property
¤
url: str
The URL for the component.
Raises RuntimeError
if the component is not public.
This is the same as calling get_component_url()
with the parent Component
class:
ComponentsSettings ¤
Bases: tuple
Settings available for django_components.
Example:
Attributes:
-
app_dirs
(Optional[Sequence[str]]
) – -
autodiscover
(Optional[bool]
) – -
cache
(Optional[str]
) – -
context_behavior
(Optional[ContextBehaviorType]
) – -
debug_highlight_components
(Optional[bool]
) – -
debug_highlight_slots
(Optional[bool]
) – -
dirs
(Optional[Sequence[Union[str, PathLike, Tuple[str, str], Tuple[str, PathLike]]]]
) – -
dynamic_component_name
(Optional[str]
) – -
extensions
(Optional[Sequence[Union[Type[ComponentExtension], str]]]
) – -
extensions_defaults
(Optional[Dict[str, Any]]
) – -
forbidden_static_files
(Optional[List[Union[str, Pattern]]]
) – -
libraries
(Optional[List[str]]
) – -
multiline_tags
(Optional[bool]
) – -
reload_on_file_change
(Optional[bool]
) – -
reload_on_template_change
(Optional[bool]
) – -
static_files_allowed
(Optional[List[Union[str, Pattern]]]
) – -
static_files_forbidden
(Optional[List[Union[str, Pattern]]]
) – -
tag_formatter
(Optional[Union[TagFormatterABC, str]]
) – -
template_cache_size
(Optional[int]
) –
app_dirs class-attribute
instance-attribute
¤
Specify the app-level directories that contain your components.
Defaults to ["components"]
. That is, for each Django app, we search <app>/components/
for components.
The paths must be relative to app, e.g.:
To search for <app>/my_comps/
.
These locations are searched during autodiscovery, or when you define HTML, JS, or CSS as separate files.
Set to empty list to disable app-level components:
autodiscover class-attribute
instance-attribute
¤
Toggle whether to run autodiscovery at the Django server startup.
Defaults to True
cache class-attribute
instance-attribute
¤
Name of the Django cache to be used for storing component's JS and CSS files.
If None
, a LocMemCache
is used with default settings.
Defaults to None
.
Read more about caching.
context_behavior class-attribute
instance-attribute
¤
context_behavior: Optional[ContextBehaviorType] = None
Configure whether, inside a component template, you can use variables from the outside ("django"
) or not ("isolated"
). This also affects what variables are available inside the {% fill %}
tags.
Also see Component context and scope.
Defaults to "django"
.
NOTE:
context_behavior
andslot_context_behavior
options were merged in v0.70.If you are migrating from BEFORE v0.67, set
context_behavior
to"django"
. From v0.67 to v0.78 (incl) the default value was"isolated"
.For v0.79 and later, the default is again
"django"
. See the rationale for change here.
debug_highlight_components class-attribute
instance-attribute
¤
DEPRECATED. Use extensions_defaults
instead. Will be removed in v1.
Enable / disable component highlighting. See Troubleshooting for more details.
Defaults to False
.
debug_highlight_slots class-attribute
instance-attribute
¤
DEPRECATED. Use extensions_defaults
instead. Will be removed in v1.
Enable / disable slot highlighting. See Troubleshooting for more details.
Defaults to False
.
dirs class-attribute
instance-attribute
¤
Specify the directories that contain your components.
Defaults to [Path(settings.BASE_DIR) / "components"]
. That is, the root components/
app.
Directories must be full paths, same as with STATICFILES_DIRS.
These locations are searched during autodiscovery, or when you define HTML, JS, or CSS as separate files.
Set to empty list to disable global components directories:
dynamic_component_name class-attribute
instance-attribute
¤
By default, the dynamic component is registered under the name "dynamic"
.
In case of a conflict, you can use this setting to change the component name used for the dynamic components.
After which you will be able to use the dynamic component with the new name:
extensions class-attribute
instance-attribute
¤
List of extensions to be loaded.
The extensions can be specified as:
- Python import path, e.g.
"path.to.my_extension.MyExtension"
. - Extension class, e.g.
my_extension.MyExtension
.
Read more about extensions.
Example:
extensions_defaults class-attribute
instance-attribute
¤
forbidden_static_files class-attribute
instance-attribute
¤
Deprecated. Use COMPONENTS.static_files_forbidden
instead.
libraries class-attribute
instance-attribute
¤
Configure extra python modules that should be loaded.
This may be useful if you are not using the autodiscovery feature, or you need to load components from non-standard locations. Thus you can have a structure of components that is independent from your apps.
Expects a list of python module paths. Defaults to empty list.
Example:
COMPONENTS = ComponentsSettings(
libraries=[
"mysite.components.forms",
"mysite.components.buttons",
"mysite.components.cards",
],
)
This would be the equivalent of importing these modules from within Django's AppConfig.ready()
:
class MyAppConfig(AppConfig):
def ready(self):
import "mysite.components.forms"
import "mysite.components.buttons"
import "mysite.components.cards"
Manually loading libraries¤
In the rare case that you need to manually trigger the import of libraries, you can use the import_libraries()
function:
multiline_tags class-attribute
instance-attribute
¤
Enable / disable multiline support for template tags. If True
, template tags like {% component %}
or {{ my_var }}
can span multiple lines.
Defaults to True
.
Disable this setting if you are making custom modifications to Django's regular expression for parsing templates at django.template.base.tag_re
.
reload_on_file_change class-attribute
instance-attribute
¤
This is relevant if you are using the project structure where HTML, JS, CSS and Python are in separate files and nested in a directory.
In this case you may notice that when you are running a development server, the server sometimes does not reload when you change component files.
Django's native live reload logic handles only Python files and HTML template files. It does NOT reload when other file types change or when template files are nested more than one level deep.
The setting reload_on_file_change
fixes this, reloading the dev server even when your component's HTML, JS, or CSS changes.
If True
, django_components configures Django to reload when files inside COMPONENTS.dirs
or COMPONENTS.app_dirs
change.
See Reload dev server on component file changes.
Defaults to False
.
Warning
This setting should be enabled only for the dev environment!
reload_on_template_change class-attribute
instance-attribute
¤
Deprecated. Use COMPONENTS.reload_on_file_change
instead.
static_files_allowed class-attribute
instance-attribute
¤
A list of file extensions (including the leading dot) that define which files within COMPONENTS.dirs
or COMPONENTS.app_dirs
are treated as static files.
If a file is matched against any of the patterns, it's considered a static file. Such files are collected when running collectstatic
, and can be accessed under the static file endpoint.
You can also pass in compiled regexes (re.Pattern
) for more advanced patterns.
By default, JS, CSS, and common image and font file formats are considered static files:
COMPONENTS = ComponentsSettings(
static_files_allowed=[
".css",
".js", ".jsx", ".ts", ".tsx",
# Images
".apng", ".png", ".avif", ".gif", ".jpg",
".jpeg", ".jfif", ".pjpeg", ".pjp", ".svg",
".webp", ".bmp", ".ico", ".cur", ".tif", ".tiff",
# Fonts
".eot", ".ttf", ".woff", ".otf", ".svg",
],
)
Warning
Exposing your Python files can be a security vulnerability. See Security notes.
static_files_forbidden class-attribute
instance-attribute
¤
A list of file extensions (including the leading dot) that define which files within COMPONENTS.dirs
or COMPONENTS.app_dirs
will NEVER be treated as static files.
If a file is matched against any of the patterns, it will never be considered a static file, even if the file matches a pattern in static_files_allowed
.
Use this setting together with static_files_allowed
for a fine control over what file types will be exposed.
You can also pass in compiled regexes (re.Pattern
) for more advanced patterns.
By default, any HTML and Python are considered NOT static files:
COMPONENTS = ComponentsSettings(
static_files_forbidden=[
".html", ".django", ".dj", ".tpl",
# Python files
".py", ".pyc",
],
)
Warning
Exposing your Python files can be a security vulnerability. See Security notes.
tag_formatter class-attribute
instance-attribute
¤
tag_formatter: Optional[Union[TagFormatterABC, str]] = None
Configure what syntax is used inside Django templates to render components. See the available tag formatters.
Defaults to "django_components.component_formatter"
.
Learn more about Customizing component tags with TagFormatter.
Can be set either as direct reference:
from django_components import component_formatter
COMPONENTS = ComponentsSettings(
"tag_formatter": component_formatter
)
Or as an import string;
Examples:
template_cache_size class-attribute
instance-attribute
¤
DEPRECATED. Template caching will be removed in v1.
Configure the maximum amount of Django templates to be cached.
Defaults to 128
.
Each time a Django template is rendered, it is cached to a global in-memory cache (using Python's lru_cache
decorator). This speeds up the next render of the component. As the same component is often used many times on the same page, these savings add up.
By default the cache holds 128 component templates in memory, which should be enough for most sites. But if you have a lot of components, or if you are overriding Component.get_template()
to render many dynamic templates, you can increase this number.
To remove the cache limit altogether and cache everything, set template_cache_size
to None
.
If you want to add templates to the cache yourself, you can use cached_template()
:
ContextBehavior ¤
Bases: str
, enum.Enum
Configure how (and whether) the context is passed to the component fills and what variables are available inside the {% fill %}
tags.
Also see Component context and scope.
Options:
django
: With this setting, component fills behave as usual Django tags.isolated
: This setting makes the component fills behave similar to Vue or React.
Attributes:
DJANGO class-attribute
instance-attribute
¤
With this setting, component fills behave as usual Django tags. That is, they enrich the context, and pass it along.
- Component fills use the context of the component they are within.
- Variables from
Component.get_template_data()
are available to the component fill.
Example:
Given this template
{% with cheese="feta" %}
{% component 'my_comp' %}
{{ my_var }} # my_var
{{ cheese }} # cheese
{% endcomponent %}
{% endwith %}
and this context returned from the Component.get_template_data()
method
Then if component "my_comp" defines context
Then this will render:
Because "my_comp" overrides the variable "my_var", so {{ my_var }}
equals 456
.
And variable "cheese" will equal feta
, because the fill CAN access the current context.
ISOLATED class-attribute
instance-attribute
¤
This setting makes the component fills behave similar to Vue or React, where the fills use EXCLUSIVELY the context variables defined in Component.get_template_data()
.
Example:
Given this template
{% with cheese="feta" %}
{% component 'my_comp' %}
{{ my_var }} # my_var
{{ cheese }} # cheese
{% endcomponent %}
{% endwith %}
and this context returned from the get_template_data()
method
Then if component "my_comp" defines context
Then this will render:
Because both variables "my_var" and "cheese" are taken from the root context. Since "cheese" is not defined in root context, it's empty.
Default dataclass
¤
Bases: object
Use this class to mark a field on the Component.Defaults
class as a factory.
Read more about Component defaults.
Example:
from django_components import Default
class MyComponent(Component):
class Defaults:
# Plain value doesn't need a factory
position = "left"
# Lists and dicts need to be wrapped in `Default`
# Otherwise all instances will share the same value
selected_items = Default(lambda: [1, 2, 3])
Attributes:
DependenciesStrategy module-attribute
¤
DependenciesStrategy = Literal['document', 'fragment', 'simple', 'prepend', 'append', 'ignore']
Type for the available strategies for rendering JS and CSS dependencies.
Read more about the dependencies strategies.
Empty ¤
Bases: tuple
Type for an object with no members.
You can use this to define Component types that accept NO args, kwargs, slots, etc:
from django_components import Component, Empty
class Table(Component):
Args = Empty
Kwargs = Empty
...
This class is a shorthand for:
Read more about Typing and validation.
ExtensionComponentConfig ¤
ExtensionComponentConfig(component: Component)
Bases: object
ExtensionComponentConfig
is the base class for all extension component configs.
Extensions can define nested classes on the component class, such as Component.View
or Component.Cache
:
This allows users to configure extension behavior per component.
Behind the scenes, the nested classes that users define on their components are merged with the extension's "base" class.
So the example above is the same as:
class MyComp(Component):
class View(ViewExtension.ComponentConfig):
def get(self, request):
...
class Cache(CacheExtension.ComponentConfig):
ttl = 60
Where both ViewExtension.ComponentConfig
and CacheExtension.ComponentConfig
are subclasses of ExtensionComponentConfig
.
Attributes:
-
component
(Component
) – -
component_class
(Type[Component]
) – -
component_cls
(Type[Component]
) –
component instance-attribute
¤
component: Component = component
FillNode ¤
FillNode(
params: List[TagAttr],
flags: Optional[Dict[str, bool]] = None,
nodelist: Optional[NodeList] = None,
node_id: Optional[str] = None,
contents: Optional[str] = None,
template_name: Optional[str] = None,
template_component: Optional[Type[Component]] = None,
)
Bases: django_components.node.BaseNode
Use {% fill %}
tag to insert content into component's slots.
{% fill %}
tag may be used only within a {% component %}..{% endcomponent %}
block, and raises a TemplateSyntaxError
if used outside of a component.
Args:
name
(str, required): Name of the slot to insert this content into. Use"default"
for the default slot.data
(str, optional): This argument allows you to access the data passed to the slot under the specified variable name. See Slot data.fallback
(str, optional): This argument allows you to access the original content of the slot under the specified variable name. See Slot fallback.
Example:
Access slot fallback¤
Use the fallback
kwarg to access the original content of the slot.
The fallback
kwarg defines the name of the variable that will contain the slot's fallback content.
Read more about Slot fallback.
Component template:
Fill:
{% component "my_table" %}
{% fill "pagination" fallback="fallback" %}
<div class="my-class">
{{ fallback }}
</div>
{% endfill %}
{% endcomponent %}
Access slot data¤
Use the data
kwarg to access the data passed to the slot.
The data
kwarg defines the name of the variable that will contain the slot's data.
Read more about Slot data.
Component template:
{# my_table.html #}
<table>
...
{% slot "pagination" pages=pages %}
< 1 | 2 | 3 >
{% endslot %}
</table>
Fill:
{% component "my_table" %}
{% fill "pagination" data="slot_data" %}
{% for page in slot_data.pages %}
<a href="{{ page.link }}">
{{ page.index }}
</a>
{% endfor %}
{% endfill %}
{% endcomponent %}
Using default slot¤
To access slot data and the fallback slot content on the default slot, use {% fill %}
with name
set to "default"
:
{% component "button" %}
{% fill name="default" data="slot_data" fallback="slot_fallback" %}
You clicked me {{ slot_data.count }} times!
{{ slot_fallback }}
{% endfill %}
{% endcomponent %}
Slot fills from Python¤
You can pass a slot fill from Python to a component by setting the body
kwarg on the {% fill %}
tag.
First pass a Slot
instance to the template with the get_template_data()
method:
from django_components import component, Slot
class Table(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_slot": Slot(lambda ctx: "Hello, world!"),
}
Then pass the slot to the {% fill %}
tag:
Warning
If you define both the body
kwarg and the {% fill %}
tag's body, an error will be raised.
Methods:
-
parse
– -
register
– -
render
– -
unregister
–
Attributes:
-
active_flags
(List[str]
) – -
allowed_flags
– -
contents
(Optional[str]
) – -
end_tag
– -
flags
(Dict[str, bool]
) – -
node_id
(str
) – -
nodelist
(NodeList
) – -
params
(List[TagAttr]
) – -
tag
– -
template_component
(Optional[Type[Component]]
) – -
template_name
(Optional[str]
) –
active_flags property
¤
Flags that were set for this specific instance as a list of strings.
E.g. the following tag:
Will have the following flags:
contents instance-attribute
¤
The contents of the tag.
This is the text between the opening and closing tags, e.g.
The contents
will be "<div> ... </div>"
.
flags instance-attribute
¤
Dictionary of all allowed_flags
that were set on the tag.
Flags that were set are True
, and the rest are False
.
E.g. the following tag:
Has 2 flags, default
and required
, but only default
was set.
The flags
dictionary will be:
You can check if a flag is set by doing:
node_id instance-attribute
¤
node_id: str = node_id or gen_id()
The unique ID of the node.
Extensions can use this ID to store additional information.
nodelist instance-attribute
¤
The nodelist of the tag.
This is the text between the opening and closing tags, e.g.
The nodelist
will contain the <div> ... </div>
part.
Unlike contents
, the nodelist
contains the actual Nodes, not just the text.
params instance-attribute
¤
params: List[TagAttr] = params
The parameters to the tag in the template.
A single param represents an arg or kwarg of the template tag.
E.g. the following tag:
Has 3 params:
- Posiitonal arg
"my_comp"
- Keyword arg
key=val
- Keyword arg
key2='val2 two'
template_component instance-attribute
¤
template_name instance-attribute
¤
The name of the Template
that contains this node.
The template name is set by Django's template loaders.
For example, the filesystem template loader will set this to the absolute path of the template file.
parse classmethod
¤
This function is what is passed to Django's Library.tag()
when registering the tag.
In other words, this method is called by Django's template parser when we encounter a tag that matches this node's tag, e.g. {% component %}
or {% slot %}
.
To register the tag, you can use BaseNode.register()
.
register classmethod
¤
A convenience method for registering the tag with the given library.
Allows you to then use the node in templates like so:
render ¤
render(
context: Context,
name: str,
*,
data: Optional[str] = None,
fallback: Optional[str] = None,
body: Optional[SlotInput] = None,
default: Optional[str] = None
) -> str
unregister classmethod
¤
Unregisters the node from the given library.
OnRenderGenerator module-attribute
¤
OnRenderGenerator = Generator[Optional[SlotResult], Tuple[Optional[SlotResult], Optional[Exception]], Optional[SlotResult]]
This is the signature of the Component.on_render()
method if it yields (and thus returns a generator).
When on_render()
is a generator then it:
-
Yields a rendered template (string or
None
) -
Receives back a tuple of
(final_output, error)
.The final output is the rendered template that now has all its children rendered too. May be
None
if you yieldedNone
earlier.The error is
None
if the rendering was successful. Otherwise the error is set and the output isNone
. -
At the end it may return a new string to override the final rendered output.
Example:
from django_components import Component, OnRenderGenerator
class MyTable(Component):
def on_render(
self,
context: Context,
template: Optional[Template],
) -> OnRenderGenerator:
# Do something BEFORE rendering template
# Same as `Component.on_render_before()`
context["hello"] = "world"
# Yield rendered template to receive fully-rendered template or error
html, error = yield template.render(context)
# Do something AFTER rendering template, or post-process
# the rendered template.
# Same as `Component.on_render_after()`
return html + "<p>Hello</p>"
ProvideNode ¤
ProvideNode(
params: List[TagAttr],
flags: Optional[Dict[str, bool]] = None,
nodelist: Optional[NodeList] = None,
node_id: Optional[str] = None,
contents: Optional[str] = None,
template_name: Optional[str] = None,
template_component: Optional[Type[Component]] = None,
)
Bases: django_components.node.BaseNode
The {% provide %}
tag is part of the "provider" part of the provide / inject feature.
Pass kwargs to this tag to define the provider's data.
Any components defined within the {% provide %}..{% endprovide %}
tags will be able to access this data with Component.inject()
.
This is similar to React's ContextProvider
, or Vue's provide()
.
Args:
name
(str, required): Provider name. This is the name you will then use inComponent.inject()
.**kwargs
: Any extra kwargs will be passed as the provided data.
Example:
Provide the "user_data" in parent component:
@register("parent")
class Parent(Component):
template = """
<div>
{% provide "user_data" user=user %}
{% component "child" / %}
{% endprovide %}
</div>
"""
def get_template_data(self, args, kwargs, slots, context):
return {
"user": kwargs["user"],
}
Since the "child" component is used within the {% provide %} / {% endprovide %}
tags, we can request the "user_data" using Component.inject("user_data")
:
@register("child")
class Child(Component):
template = """
<div>
User is: {{ user }}
</div>
"""
def get_template_data(self, args, kwargs, slots, context):
user = self.inject("user_data").user
return {
"user": user,
}
Notice that the keys defined on the {% provide %}
tag are then accessed as attributes when accessing them with Component.inject()
.
✅ Do this
❌ Don't do this
Methods:
-
parse
– -
register
– -
render
– -
unregister
–
Attributes:
-
active_flags
(List[str]
) – -
allowed_flags
– -
contents
(Optional[str]
) – -
end_tag
– -
flags
(Dict[str, bool]
) – -
node_id
(str
) – -
nodelist
(NodeList
) – -
params
(List[TagAttr]
) – -
tag
– -
template_component
(Optional[Type[Component]]
) – -
template_name
(Optional[str]
) –
active_flags property
¤
Flags that were set for this specific instance as a list of strings.
E.g. the following tag:
Will have the following flags:
contents instance-attribute
¤
The contents of the tag.
This is the text between the opening and closing tags, e.g.
The contents
will be "<div> ... </div>"
.
flags instance-attribute
¤
Dictionary of all allowed_flags
that were set on the tag.
Flags that were set are True
, and the rest are False
.
E.g. the following tag:
Has 2 flags, default
and required
, but only default
was set.
The flags
dictionary will be:
You can check if a flag is set by doing:
node_id instance-attribute
¤
node_id: str = node_id or gen_id()
The unique ID of the node.
Extensions can use this ID to store additional information.
nodelist instance-attribute
¤
The nodelist of the tag.
This is the text between the opening and closing tags, e.g.
The nodelist
will contain the <div> ... </div>
part.
Unlike contents
, the nodelist
contains the actual Nodes, not just the text.
params instance-attribute
¤
params: List[TagAttr] = params
The parameters to the tag in the template.
A single param represents an arg or kwarg of the template tag.
E.g. the following tag:
Has 3 params:
- Posiitonal arg
"my_comp"
- Keyword arg
key=val
- Keyword arg
key2='val2 two'
template_component instance-attribute
¤
template_name instance-attribute
¤
The name of the Template
that contains this node.
The template name is set by Django's template loaders.
For example, the filesystem template loader will set this to the absolute path of the template file.
parse classmethod
¤
This function is what is passed to Django's Library.tag()
when registering the tag.
In other words, this method is called by Django's template parser when we encounter a tag that matches this node's tag, e.g. {% component %}
or {% slot %}
.
To register the tag, you can use BaseNode.register()
.
register classmethod
¤
A convenience method for registering the tag with the given library.
Allows you to then use the node in templates like so:
unregister classmethod
¤
Unregisters the node from the given library.
RegistrySettings ¤
Bases: tuple
Configuration for a ComponentRegistry
.
These settings define how the components registered with this registry will behave when rendered.
from django_components import ComponentRegistry, RegistrySettings
registry_settings = RegistrySettings(
context_behavior="django",
tag_formatter="django_components.component_shorthand_formatter",
)
registry = ComponentRegistry(settings=registry_settings)
Attributes:
-
CONTEXT_BEHAVIOR
(Optional[ContextBehaviorType]
) – -
TAG_FORMATTER
(Optional[Union[TagFormatterABC, str]]
) – -
context_behavior
(Optional[ContextBehaviorType]
) – -
tag_formatter
(Optional[Union[TagFormatterABC, str]]
) –
CONTEXT_BEHAVIOR class-attribute
instance-attribute
¤
CONTEXT_BEHAVIOR: Optional[ContextBehaviorType] = None
Deprecated. Use context_behavior
instead. Will be removed in v1.
Same as the global COMPONENTS.context_behavior
setting, but for this registry.
If omitted, defaults to the global COMPONENTS.context_behavior
setting.
TAG_FORMATTER class-attribute
instance-attribute
¤
TAG_FORMATTER: Optional[Union[TagFormatterABC, str]] = None
Deprecated. Use tag_formatter
instead. Will be removed in v1.
Same as the global COMPONENTS.tag_formatter
setting, but for this registry.
If omitted, defaults to the global COMPONENTS.tag_formatter
setting.
context_behavior class-attribute
instance-attribute
¤
context_behavior: Optional[ContextBehaviorType] = None
Same as the global COMPONENTS.context_behavior
setting, but for this registry.
If omitted, defaults to the global COMPONENTS.context_behavior
setting.
tag_formatter class-attribute
instance-attribute
¤
tag_formatter: Optional[Union[TagFormatterABC, str]] = None
Same as the global COMPONENTS.tag_formatter
setting, but for this registry.
If omitted, defaults to the global COMPONENTS.tag_formatter
setting.
Slot dataclass
¤
Slot(
contents: Any,
content_func: SlotFunc[TSlotData] = cast(SlotFunc[TSlotData], None),
component_name: Optional[str] = None,
slot_name: Optional[str] = None,
nodelist: Optional[NodeList] = None,
fill_node: Optional[Union[FillNode, ComponentNode]] = None,
extra: Dict[str, Any] = dict(),
)
Bases: typing.Generic
This class is the main way for defining and handling slots.
It holds the slot content function along with related metadata.
Read more about Slot class.
Example:
Passing slots to components:
from django_components import Slot
slot = Slot(lambda ctx: f"Hello, {ctx.data['name']}!")
MyComponent.render(
slots={
"my_slot": slot,
},
)
Accessing slots inside the components:
from django_components import Component
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
my_slot = slots["my_slot"]
return {
"my_slot": my_slot,
}
Rendering slots:
from django_components import Slot
slot = Slot(lambda ctx: f"Hello, {ctx.data['name']}!")
html = slot({"name": "John"}) # Output: Hello, John!
Attributes:
-
component_name
(Optional[str]
) – -
content_func
(SlotFunc[TSlotData]
) – -
contents
(Any
) – -
do_not_call_in_templates
(bool
) – -
extra
(Dict[str, Any]
) – -
fill_node
(Optional[Union[FillNode, ComponentNode]]
) – -
nodelist
(Optional[NodeList]
) – -
slot_name
(Optional[str]
) –
component_name class-attribute
instance-attribute
¤
content_func class-attribute
instance-attribute
¤
The actual slot function.
Do NOT call this function directly, instead call the Slot
instance as a function.
Read more about Rendering slot functions.
contents instance-attribute
¤
contents: Any
The original value that was passed to the Slot
constructor.
- If Slot was created from
{% fill %}
tag,Slot.contents
will contain the body (string) of that{% fill %}
tag. - If Slot was created from string as
Slot("...")
,Slot.contents
will contain that string. - If Slot was created from a function,
Slot.contents
will contain that function.
Read more about Slot contents.
do_not_call_in_templates property
¤
do_not_call_in_templates: bool
Django special property to prevent calling the instance as a function inside Django templates.
extra class-attribute
instance-attribute
¤
Dictionary that can be used to store arbitrary metadata about the slot.
See Slot metadata.
See Pass slot metadata for usage for extensions.
Example:
fill_node class-attribute
instance-attribute
¤
fill_node: Optional[Union[FillNode, ComponentNode]] = None
If the slot was created from a {% fill %}
tag, this will be the FillNode
instance.
If the slot was a default slot created from a {% component %}
tag, this will be the ComponentNode
instance.
Otherwise, this will be None
.
Extensions can use this info to handle slots differently based on their source.
See Slot metadata.
Example:
You can use this to find the Component
in whose template the {% fill %}
tag was defined:
nodelist class-attribute
instance-attribute
¤
nodelist: Optional[NodeList] = None
If the slot was defined with {% fill %}
tag, this will be the Nodelist of the fill's content.
See Slot metadata.
slot_name class-attribute
instance-attribute
¤
SlotContent module-attribute
¤
SlotContent = SlotInput[TSlotData]
DEPRECATED: Use SlotInput
instead. Will be removed in v1.
SlotContext dataclass
¤
SlotContext(data: TSlotData, fallback: Optional[Union[str, SlotFallback]] = None, context: Optional[Context] = None)
Bases: typing.Generic
Metadata available inside slot functions.
Read more about Slot functions.
Example:
from django_components import SlotContext, SlotResult
def my_slot(ctx: SlotContext) -> SlotResult:
return f"Hello, {ctx.data['name']}!"
You can pass a type parameter to the SlotContext
to specify the type of the data passed to the slot:
class MySlotData(TypedDict):
name: str
def my_slot(ctx: SlotContext[MySlotData]):
return f"Hello, {ctx.data['name']}!"
Attributes:
context class-attribute
instance-attribute
¤
Django template Context
available inside the {% fill %}
tag.
May be None
if you call the slot fill directly, without using {% slot %}
tags.
fallback class-attribute
instance-attribute
¤
fallback: Optional[Union[str, SlotFallback]] = None
Slot's fallback content. Lazily-rendered - coerce this value to string to force it to render.
Read more about Slot fallback.
Example:
May be None
if you call the slot fill directly, without using {% slot %}
tags.
SlotFallback ¤
Bases: object
The content between the {% slot %}..{% endslot %}
tags is the fallback content that will be rendered if no fill is given for the slot.
Because the fallback is defined as a piece of the template (NodeList
), we want to lazily render it only when needed.
SlotFallback
type allows to pass around the slot fallback as a variable.
To force the fallback to render, coerce it to string to trigger the __str__()
method.
Example:
SlotFunc ¤
Bases: typing.Protocol
When rendering components with Component.render()
or Component.render_to_response()
, the slots can be given either as strings or as functions.
If a slot is given as a function, it will have the signature of SlotFunc
.
Read more about Slot functions.
Parameters:
-
ctx
(SlotContext
) –Single named tuple that holds the slot data and metadata.
Returns:
-
str | SafeString
–The rendered slot content.
Example:
from django_components import SlotContext, SlotResult
def header(ctx: SlotContext) -> SlotResult:
if ctx.data.get("name"):
return f"Hello, {ctx.data['name']}!"
else:
return ctx.fallback
html = MyTable.render(
slots={
"header": header,
},
)
SlotInput module-attribute
¤
SlotInput = Union[SlotResult, SlotFunc[TSlotData], Slot[TSlotData]]
Type representing all forms in which slot content can be passed to a component.
When rendering a component with Component.render()
or Component.render_to_response()
, the slots may be given a strings, functions, or Slot
instances. This type describes that union.
Use this type when typing the slots in your component.
SlotInput
accepts an optional type parameter to specify the data dictionary that will be passed to the slot content function.
Example:
from typing import NamedTuple
from typing_extensions import TypedDict
from django_components import Component, SlotInput
class TableFooterSlotData(TypedDict):
page_number: int
class Table(Component):
class Slots(NamedTuple):
header: SlotInput
footer: SlotInput[TableFooterSlotData]
template = "<div>{% slot 'footer' %}</div>"
html = Table.render(
slots={
# As a string
"header": "Hello, World!",
# Safe string
"header": mark_safe("<i><am><safe>"),
# Function
"footer": lambda ctx: f"Page: {ctx.data['page_number']}!",
# Slot instance
"footer": Slot(lambda ctx: f"Page: {ctx.data['page_number']}!"),
# None (Same as no slot)
"header": None,
},
)
SlotNode ¤
SlotNode(
params: List[TagAttr],
flags: Optional[Dict[str, bool]] = None,
nodelist: Optional[NodeList] = None,
node_id: Optional[str] = None,
contents: Optional[str] = None,
template_name: Optional[str] = None,
template_component: Optional[Type[Component]] = None,
)
Bases: django_components.node.BaseNode
{% slot %}
tag marks a place inside a component where content can be inserted from outside.
Learn more about using slots.
This is similar to slots as seen in Web components, Vue or React's children
.
Args:
name
(str, required): Registered name of the component to renderdefault
: Optional flag. If there is a default slot, you can pass the component slot content without using the{% fill %}
tag. See Default slotrequired
: Optional flag. Will raise an error if a slot is required but not given.**kwargs
: Any extra kwargs will be passed as the slot data.
Example:
@register("child")
class Child(Component):
template = """
<div>
{% slot "content" default %}
This is shown if not overriden!
{% endslot %}
</div>
<aside>
{% slot "sidebar" required / %}
</aside>
"""
@register("parent")
class Parent(Component):
template = """
<div>
{% component "child" %}
{% fill "content" %}
🗞️📰
{% endfill %}
{% fill "sidebar" %}
🍷🧉🍾
{% endfill %}
{% endcomponent %}
</div>
"""
Slot data¤
Any extra kwargs will be considered as slot data, and will be accessible in the {% fill %}
tag via fill's data
kwarg:
Read more about Slot data.
@register("child")
class Child(Component):
template = """
<div>
{# Passing data to the slot #}
{% slot "content" user=user %}
This is shown if not overriden!
{% endslot %}
</div>
"""
@register("parent")
class Parent(Component):
template = """
{# Parent can access the slot data #}
{% component "child" %}
{% fill "content" data="data" %}
<div class="wrapper-class">
{{ data.user }}
</div>
{% endfill %}
{% endcomponent %}
"""
Slot fallback¤
The content between the {% slot %}..{% endslot %}
tags is the fallback content that will be rendered if no fill is given for the slot.
This fallback content can then be accessed from within the {% fill %}
tag using the fill's fallback
kwarg. This is useful if you need to wrap / prepend / append the original slot's content.
@register("child")
class Child(Component):
template = """
<div>
{% slot "content" %}
This is fallback content!
{% endslot %}
</div>
"""
@register("parent")
class Parent(Component):
template = """
{# Parent can access the slot's fallback content #}
{% component "child" %}
{% fill "content" fallback="fallback" %}
{{ fallback }}
{% endfill %}
{% endcomponent %}
"""
Methods:
-
parse
– -
register
– -
render
– -
unregister
–
Attributes:
-
active_flags
(List[str]
) – -
allowed_flags
– -
contents
(Optional[str]
) – -
end_tag
– -
flags
(Dict[str, bool]
) – -
node_id
(str
) – -
nodelist
(NodeList
) – -
params
(List[TagAttr]
) – -
tag
– -
template_component
(Optional[Type[Component]]
) – -
template_name
(Optional[str]
) –
active_flags property
¤
Flags that were set for this specific instance as a list of strings.
E.g. the following tag:
Will have the following flags:
allowed_flags class-attribute
instance-attribute
¤
contents instance-attribute
¤
The contents of the tag.
This is the text between the opening and closing tags, e.g.
The contents
will be "<div> ... </div>"
.
flags instance-attribute
¤
Dictionary of all allowed_flags
that were set on the tag.
Flags that were set are True
, and the rest are False
.
E.g. the following tag:
Has 2 flags, default
and required
, but only default
was set.
The flags
dictionary will be:
You can check if a flag is set by doing:
node_id instance-attribute
¤
node_id: str = node_id or gen_id()
The unique ID of the node.
Extensions can use this ID to store additional information.
nodelist instance-attribute
¤
The nodelist of the tag.
This is the text between the opening and closing tags, e.g.
The nodelist
will contain the <div> ... </div>
part.
Unlike contents
, the nodelist
contains the actual Nodes, not just the text.
params instance-attribute
¤
params: List[TagAttr] = params
The parameters to the tag in the template.
A single param represents an arg or kwarg of the template tag.
E.g. the following tag:
Has 3 params:
- Posiitonal arg
"my_comp"
- Keyword arg
key=val
- Keyword arg
key2='val2 two'
template_component instance-attribute
¤
template_name instance-attribute
¤
The name of the Template
that contains this node.
The template name is set by Django's template loaders.
For example, the filesystem template loader will set this to the absolute path of the template file.
parse classmethod
¤
This function is what is passed to Django's Library.tag()
when registering the tag.
In other words, this method is called by Django's template parser when we encounter a tag that matches this node's tag, e.g. {% component %}
or {% slot %}
.
To register the tag, you can use BaseNode.register()
.
register classmethod
¤
A convenience method for registering the tag with the given library.
Allows you to then use the node in templates like so:
unregister classmethod
¤
Unregisters the node from the given library.
SlotRef module-attribute
¤
SlotRef = SlotFallback
DEPRECATED: Use SlotFallback
instead. Will be removed in v1.
SlotResult module-attribute
¤
SlotResult = Union[str, SafeString]
Type representing the result of a slot render function.
Example:
from django_components import SlotContext, SlotResult
def my_slot_fn(ctx: SlotContext) -> SlotResult:
return "Hello, world!"
my_slot = Slot(my_slot_fn)
html = my_slot() # Output: Hello, world!
Read more about Slot functions.
TagFormatterABC ¤
Bases: abc.ABC
Abstract base class for defining custom tag formatters.
Tag formatters define how the component tags are used in the template.
Read more about Tag formatter.
For example, with the default tag formatter (ComponentFormatter
), components are written as:
While with the shorthand tag formatter (ShorthandComponentFormatter
), components are written as:
Example:
Implementation for ShorthandComponentFormatter
:
from djagno_components import TagFormatterABC, TagResult
class ShorthandComponentFormatter(TagFormatterABC):
def start_tag(self, name: str) -> str:
return name
def end_tag(self, name: str) -> str:
return f"end{name}"
def parse(self, tokens: List[str]) -> TagResult:
tokens = [*tokens]
name = tokens.pop(0)
return TagResult(name, tokens)
Methods:
end_tag abstractmethod
¤
parse abstractmethod
¤
Given the tokens (words) passed to a component start tag, this function extracts the component name from the tokens list, and returns TagResult
, which is a tuple of (component_name, remaining_tokens)
.
Parameters:
-
tokens
([List(str]
) –List of tokens passed to the component tag.
Returns:
-
TagResult
(TagResult
) –Parsed component name and remaining tokens.
Example:
Assuming we used a component in a template like this:
This function receives a list of tokens:
component
is the tag name, which we drop."my_comp"
is the component name, but we must remove the extra quotes.- The remaining tokens we pass unmodified, as that's the input to the component.
So in the end, we return:
TagResult ¤
Bases: tuple
The return value from TagFormatter.parse()
.
Read more about Tag formatter.
Attributes:
-
component_name
(str
) – -
tokens
(List[str]
) –
component_name instance-attribute
¤
component_name: str
Component name extracted from the template tag
For example, if we had tag
Then component_name
would be my_comp
.
tokens instance-attribute
¤
Remaining tokens (words) that were passed to the tag, with component name removed
For example, if we had tag
Then tokens
would be ['key=val', 'key2=val2']
.
all_registries ¤
all_registries() -> List[ComponentRegistry]
Get a list of all created ComponentRegistry
instances.
autodiscover ¤
Search for all python files in COMPONENTS.dirs
and COMPONENTS.app_dirs
and import them.
See Autodiscovery.
NOTE: Subdirectories and files starting with an underscore _
(except for __init__.py
are ignored.
Parameters:
-
map_module
(Callable[[str], str]
, default:None
) –Map the module paths with
map_module
function. This serves as an escape hatch for when you need to use this function in tests.
Returns:
To get the same list of modules that autodiscover()
would return, but without importing them, use get_component_files()
:
cached_template ¤
cached_template(
template_string: str,
template_cls: Optional[Type[Template]] = None,
origin: Optional[Origin] = None,
name: Optional[str] = None,
engine: Optional[Any] = None,
) -> Template
DEPRECATED. Template caching will be removed in v1.
Create a Template instance that will be cached as per the COMPONENTS.template_cache_size
setting.
Parameters:
-
template_string
(str
) –Template as a string, same as the first argument to Django's
Template
. Required. -
template_cls
(Type[Template]
, default:None
) –Specify the Template class that should be instantiated. Defaults to Django's
Template
class. -
origin
(Type[Origin]
, default:None
) –Sets
Template.Origin
. -
name
(Type[str]
, default:None
) –Sets
Template.name
-
engine
(Type[Any]
, default:None
) –Sets
Template.engine
from django_components import cached_template
template = cached_template("Variable: {{ variable }}")
# You can optionally specify Template class, and other Template inputs:
class MyTemplate(Template):
pass
template = cached_template(
"Variable: {{ variable }}",
template_cls=MyTemplate,
name=...
origin=...
engine=...
)
format_attributes ¤
Format a dict of attributes into an HTML attributes string.
Read more about HTML attributes.
Example:
will return
get_component_by_class_id ¤
Get a component class by its unique ID.
Each component class is associated with a unique hash that's derived from its module import path.
E.g. path.to.my.secret.MyComponent
-> MyComponent_ab01f32
This hash is available under class_id
on the component class.
Raises KeyError
if the component class is not found.
NOTE: This is mainly intended for extensions.
get_component_dirs ¤
Get directories that may contain component files.
This is the heart of all features that deal with filesystem and file lookup. Autodiscovery, Django template resolution, static file resolution - They all use this.
Parameters:
-
include_apps
(bool
, default:True
) –Include directories from installed Django apps. Defaults to
True
.
Returns:
get_component_dirs()
searches for dirs set in COMPONENTS.dirs
settings. If none set, defaults to searching for a "components"
app.
In addition to that, also all installed Django apps are checked whether they contain directories as set in COMPONENTS.app_dirs
(e.g. [app]/components
).
Notes:
-
Paths that do not point to directories are ignored.
-
BASE_DIR
setting is required. -
The paths in
COMPONENTS.dirs
must be absolute paths.
get_component_files ¤
get_component_files(suffix: Optional[str] = None) -> List[ComponentFileEntry]
Search for files within the component directories (as defined in get_component_dirs()
).
Requires BASE_DIR
setting to be set.
Subdirectories and files starting with an underscore _
(except __init__.py
) are ignored.
Parameters:
-
suffix
(Optional[str]
, default:None
) –The suffix to search for. E.g.
.py
,.js
,.css
. Defaults toNone
, which will search for all files.
Returns:
-
List[ComponentFileEntry]
–List[ComponentFileEntry] A list of entries that contain both the filesystem path and the python import path (dot path).
Example:
get_component_url ¤
get_component_url(component: Union[Type[Component], Component], query: Optional[Dict] = None, fragment: Optional[str] = None) -> str
Get the URL for a Component
.
Raises RuntimeError
if the component is not public.
Read more about Component views and URLs.
get_component_url()
optionally accepts query
and fragment
arguments.
Example:
import_libraries ¤
Import modules set in COMPONENTS.libraries
setting.
See Autodiscovery.
Parameters:
-
map_module
(Callable[[str], str]
, default:None
) –Map the module paths with
map_module
function. This serves as an escape hatch for when you need to use this function in tests.
Returns:
Examples:
Normal usage - load libraries after Django has loaded
from django_components import import_libraries
class MyAppConfig(AppConfig):
def ready(self):
import_libraries()
Potential usage in tests
merge_attributes ¤
Merge a list of dictionaries into a single dictionary.
The dictionaries are treated as HTML attributes and are merged accordingly:
- If a same key is present in multiple dictionaries, the values are joined with a space character.
- The
class
andstyle
keys are handled specially, similar to how Vue does it.
Read more about HTML attributes.
Example:
merge_attributes(
{"my-attr": "my-value", "class": "my-class"},
{"my-attr": "extra-value", "data-id": "123"},
)
will result in
The class
attribute
The class
attribute can be given as a string, or a dictionary.
- If given as a string, it is used as is.
- If given as a dictionary, only the keys with a truthy value are used.
Example:
will result in
The style
attribute
The style
attribute can be given as a string, a list, or a dictionary.
- If given as a string, it is used as is.
- If given as a dictionary, it is converted to a style attribute string.
Example:
merge_attributes(
{"style": "color: red; background-color: blue;"},
{"style": {"background-color": "green", "color": False}},
)
will result in
register ¤
register(name: str, registry: Optional[ComponentRegistry] = None) -> Callable[[Type[TComponent]], Type[TComponent]]
Class decorator for registering a component to a component registry.
Parameters:
-
name
(str
) –Registered name. This is the name by which the component will be accessed from within a template when using the
{% component %}
tag. Required. -
registry
(ComponentRegistry
, default:None
) –Specify the registry to which to register this component. If omitted, component is registered to the default registry.
Raises:
-
AlreadyRegistered
–If there is already a component registered under the same name.
Examples:
from django_components import Component, register
@register("my_component")
class MyComponent(Component):
...
Specifing ComponentRegistry
the component should be registered to by setting the registry
kwarg:
registry module-attribute
¤
registry: ComponentRegistry = ComponentRegistry()
The default and global component registry. Use this instance to directly register or remove components:
# Register components
registry.register("button", ButtonComponent)
registry.register("card", CardComponent)
# Get single
registry.get("button")
# Get all
registry.all()
# Check if component is registered
registry.has("button")
# Unregister single
registry.unregister("button")
# Unregister all
registry.clear()
render_dependencies ¤
render_dependencies(content: TContent, strategy: DependenciesStrategy = 'document') -> TContent
Given a string that contains parts that were rendered by components, this function inserts all used JS and CSS.
By default, the string is parsed as an HTML and: - CSS is inserted at the end of <head>
(if present) - JS is inserted at the end of <body>
(if present)
If you used {% component_js_dependencies %}
or {% component_css_dependencies %}
, then the JS and CSS will be inserted only at these locations.
Example:
def my_view(request):
template = Template('''
{% load components %}
<!doctype html>
<html>
<head></head>
<body>
<h1>{{ table_name }}</h1>
{% component "table" name=table_name / %}
</body>
</html>
''')
html = template.render(
Context({
"table_name": request.GET["name"],
})
)
# This inserts components' JS and CSS
processed_html = render_dependencies(html)
return HttpResponse(processed_html)
template_tag ¤
template_tag(
library: Library, tag: str, end_tag: Optional[str] = None, allowed_flags: Optional[List[str]] = None
) -> Callable[[Callable], Callable]
A simplified version of creating a template tag based on BaseNode
.
Instead of defining the whole class, you can just define the render()
method.
from django.template import Context, Library
from django_components import BaseNode, template_tag
library = Library()
@template_tag(
library,
tag="mytag",
end_tag="endmytag",
allowed_flags=["required"],
)
def mytag(node: BaseNode, context: Context, name: str, **kwargs: Any) -> str:
return f"Hello, {name}!"
This will allow the template tag {% mytag %}
to be used like this:
The given function will be wrapped in a class that inherits from BaseNode
.
And this class will be registered with the given library.
The function MUST accept at least two positional arguments: node
and context
Any extra parameters defined on this function will be part of the tag's input parameters.
For more info, see BaseNode.render()
.