Skip to content

Components API Reference

All component base classes live in dj_design_system.components. Any new component class added to that module will appear here automatically.

dj_design_system.components

BaseComponent(**kwargs)

Source code in dj_design_system/components.py
54
55
56
57
58
59
60
def __init__(self, **kwargs):
    self.context = {}
    for var_name, var_value in kwargs.items():
        setattr(self, var_name, var_value)

    self._validate_meta_constraints()
    self.validate_params()

__init_subclass__(**kwargs)

Validate Meta constraint declarations at class definition time.

Source code in dj_design_system/components.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def __init_subclass__(cls, **kwargs) -> None:
    """Validate Meta constraint declarations at class definition time."""
    super().__init_subclass__(**kwargs)

    if is_abstract(cls):
        return

    meta = get_own_meta(cls)
    param_names = set(cls.get_params().keys())

    for a, b in getattr(meta, "mutually_exclusive", []):
        for name in (a, b):
            if name not in param_names:
                raise ValueError(
                    f"{cls.__name__}.Meta.mutually_exclusive references unknown param '{name}'."
                )

    for dependent, dependency in getattr(meta, "requires", []):
        for name in (dependent, dependency):
            if name not in param_names:
                raise ValueError(
                    f"{cls.__name__}.Meta.requires references unknown param '{name}'."
                )

docstring() classmethod

Return a string describing the API of this component, including its parameters and their types.

Source code in dj_design_system/components.py
136
137
138
139
140
141
142
143
144
145
@classmethod
def docstring(cls) -> str:
    """Return a string describing the API of this component, including its parameters and their types."""
    params = cls.get_params()
    api_docs = f"{cls.__doc__}\n\n"
    if len(params) > 0:
        api_docs += "Parameters:\n"
    for parameter_spec in params.values():
        api_docs += f"- {parameter_spec.docstring()}\n"
    return api_docs

get_app_label() classmethod

Return the app label this component was discovered in.

Source code in dj_design_system/components.py
154
155
156
157
158
159
@classmethod
def get_app_label(cls) -> str:
    """Return the app label this component was discovered in."""
    from dj_design_system import component_registry

    return component_registry.get_info(cls).app_label

get_available_themes() classmethod

Return the list of theme values supported by this component.

Source code in dj_design_system/components.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
@classmethod
def get_available_themes(cls) -> list[str]:
    """Return the list of theme values supported by this component."""
    meta = get_own_meta(cls)
    available = getattr(meta, "available_themes", None)
    if isinstance(available, str):
        return [available]
    if available is not None:
        return list(available)

    app_label = cls.get_app_label()
    app_themes = (dds_settings.APP_THEMES or {}).get(app_label)
    if isinstance(app_themes, str):
        return [app_themes]
    if app_themes is not None:
        return list(app_themes)

    return [t.value for t in get_themes()]

get_classes_string()

Get a string of CSS classes based on the context.

Source code in dj_design_system/components.py
 97
 98
 99
100
101
102
103
def get_classes_string(self):
    """Get a string of CSS classes based on the context."""
    classes = []
    for param_name, spec in self.params.items():
        param_value = getattr(self, param_name)
        classes.extend(spec.get_css_classes(param_name, param_value))
    return " ".join(classes)

get_context()

Get the context for rendering the component.

Source code in dj_design_system/components.py
88
89
90
91
92
93
94
95
def get_context(self) -> dict[str, Any]:
    """Get the context for rendering the component."""
    self.context["classes"] = self.get_classes_string()
    for param_name, spec in self.params.items():
        value = getattr(self, param_name)
        self.context[param_name] = value
        self.context.update(spec.get_extra_context(param_name, value))
    return self.context

get_media() classmethod

Return the CSS and JS static URL paths required by this component.

Source code in dj_design_system/components.py
168
169
170
171
172
173
@classmethod
def get_media(cls) -> "ComponentMedia":
    """Return the CSS and JS static URL paths required by this component."""
    from dj_design_system import component_registry

    return component_registry.get_info(cls).media

get_name() classmethod

Return the component's registered name from the registry.

Source code in dj_design_system/components.py
147
148
149
150
151
152
@classmethod
def get_name(cls) -> str:
    """Return the component's registered name from the registry."""
    from dj_design_system import component_registry

    return component_registry.get_info(cls).name

get_params() classmethod

Get the parameters for this component.

Source code in dj_design_system/components.py
126
127
128
129
130
131
132
133
134
@classmethod
def get_params(cls) -> dict[str, "BaseParam"]:
    """Get the parameters for this component."""
    result = {}
    for klass in cls.__mro__:
        for attr_name, attr_value in vars(klass).items():
            if isinstance(attr_value, BaseParam) and attr_name not in result:
                result[attr_name] = attr_value
    return result

get_positional_args() classmethod

Return the list of positional arg names from the class's own Meta.positional_args.

Source code in dj_design_system/components.py
175
176
177
178
179
180
@classmethod
def get_positional_args(cls) -> list[str]:
    """Return the list of positional arg names from the class's own Meta.positional_args."""
    meta = get_own_meta(cls)
    positional = getattr(meta, "positional_args", None)
    return list(positional) if positional else []

get_relative_path() classmethod

Return the relative path within the app's components directory.

Source code in dj_design_system/components.py
161
162
163
164
165
166
@classmethod
def get_relative_path(cls) -> str:
    """Return the relative path within the app's components directory."""
    from dj_design_system import component_registry

    return component_registry.get_info(cls).relative_path

map_positional_args(positional_args, args, kwargs) staticmethod

Map positional arguments to keyword arguments using the positional_args spec.

Source code in dj_design_system/components.py
201
202
203
204
205
206
207
208
209
@staticmethod
def map_positional_args(
    positional_args: list[str], args: tuple, kwargs: dict
) -> dict:
    """Map positional arguments to keyword arguments using the positional_args spec."""
    for i, arg_name in enumerate(positional_args):
        if i < len(args):
            kwargs[arg_name] = args[i]
    return kwargs

render()

Render the component as an HTML string.

Source code in dj_design_system/components.py
105
106
107
108
109
110
def render(self) -> str:
    """Render the component as an HTML string."""
    template_name: str | None = getattr(type(self), "_template_name", None)
    if template_name:
        return mark_safe(render_to_string(template_name, self.get_context()))
    return format_html(format_string=self.template_format_str, **self.get_context())

validate_params()

An override hook allowing param combinations or values to raise exceptions if necessary

Source code in dj_design_system/components.py
62
63
64
def validate_params(self) -> None:
    """An override hook allowing param combinations or values to raise exceptions if necessary"""
    ...

BlockComponent(content=None, *, slots=None, **kwargs)

Bases: BaseComponent

A component registered as a Django simple_block_tag.

Source code in dj_design_system/components.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
def __init__(
    self,
    content: SafeString | None = None,
    *,
    slots: dict[str, SafeString] | None = None,
    **kwargs,
):
    if self.has_slots():
        if slots is None:
            slots = {}
        tag_name = get_meta_name(type(self)) or derive_name(type(self))
        self.slots = validate_slots(self.get_slots(), slots, tag_name)
        self.content = None
    else:
        self.content = content
        self.slots = {}
    super().__init__(**kwargs)

as_tag() classmethod

Return a template tag function or compilation function.

Source code in dj_design_system/components.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
@classmethod
def as_tag(cls):
    """Return a template tag function or compilation function."""
    if cls.has_slots():
        tag_name = get_meta_name(cls) or derive_name(cls)
        return make_slotted_block_tag(cls, tag_name)

    positional_args = cls.get_positional_args()

    def _tag(content, *args, **kwargs):
        cls.map_positional_args(positional_args, args, kwargs)
        return cls(content=content, **kwargs)

    return _tag

get_context()

Add content or slot values to the context automatically.

Source code in dj_design_system/components.py
256
257
258
259
260
261
262
263
264
def get_context(self) -> dict[str, Any]:
    """Add ``content`` or slot values to the context automatically."""
    context = super().get_context()
    if self.has_slots():
        for name, value in self.slots.items():
            context[name] = value
    else:
        context["content"] = self.content
    return context

get_slots() classmethod

Return the declared slots dict from Meta, or empty dict.

Source code in dj_design_system/components.py
272
273
274
275
276
@classmethod
def get_slots(cls) -> dict[str, "Slot"]:
    """Return the declared slots dict from Meta, or empty dict."""
    meta = get_own_meta(cls)
    return dict(getattr(meta, "slots", {}))

has_slots() classmethod

Return True if this component declares named slots via Meta.slots.

Source code in dj_design_system/components.py
266
267
268
269
270
@classmethod
def has_slots(cls) -> bool:
    """Return True if this component declares named slots via Meta.slots."""
    meta = get_own_meta(cls)
    return bool(getattr(meta, "slots", None))

TagComponent(**kwargs)

Bases: BaseComponent

A component registered as a Django simple_tag.

Source code in dj_design_system/components.py
54
55
56
57
58
59
60
def __init__(self, **kwargs):
    self.context = {}
    for var_name, var_value in kwargs.items():
        setattr(self, var_name, var_value)

    self._validate_meta_constraints()
    self.validate_params()

as_tag() classmethod

Return a template tag function mapping positional args via Meta.positional_args.

Source code in dj_design_system/components.py
218
219
220
221
222
223
224
225
226
227
@classmethod
def as_tag(cls):
    """Return a template tag function mapping positional args via Meta.positional_args."""
    positional_args = cls.get_positional_args()

    def _tag(*args, **kwargs):
        cls.map_positional_args(positional_args, args, kwargs)
        return cls(**kwargs)

    return _tag

options: members: true show_root_heading: false show_source: true show_symbol_type_heading: true show_symbol_type_toc: true docstring_style: google merge_init_into_class: true group_by_category: true


Slots API

dj_design_system.slots

Named slot support for BlockComponent.

A slot defines a named content area that template authors fill using {% slot "name" %}...{% endslot %} tags inside a block component.

Slot(required=False, default='', description='')

Declaration of a named content slot on a BlockComponent.

Parameters:

Name Type Description Default
required bool

Whether the slot must be provided. Defaults to False.

False
default str

Default content when the slot is not provided. Only meaningful when required=False.

''
description str

Human-readable description for documentation/gallery.

''
Source code in dj_design_system/slots.py
25
26
27
28
29
30
31
32
33
def __init__(
    self,
    required: bool = False,
    default: str = "",
    description: str = "",
) -> None:
    self.required = required
    self.default = default
    self.description = description

validate_slots(declared_slots, provided_slots, component_name)

Validate provided slots against a component's declared slots.

Returns a complete dict of slot values (filling in defaults for missing optional slots).

Raises:

Type Description
ValueError

If a required slot is missing, an unknown slot name is used, or a slot name appears more than once.

Source code in dj_design_system/slots.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def validate_slots(
    declared_slots: dict[str, Slot],
    provided_slots: dict[str, str],
    component_name: str,
) -> dict[str, str]:
    """Validate provided slots against a component's declared slots.

    Returns a complete dict of slot values (filling in defaults for
    missing optional slots).

    Raises:
        ValueError: If a required slot is missing, an unknown slot name
            is used, or a slot name appears more than once.
    """
    # Check for unknown slot names
    unknown = set(provided_slots) - set(declared_slots)
    if unknown:
        names = ", ".join(sorted(unknown))
        valid = ", ".join(sorted(declared_slots))
        raise ValueError(
            f"'{component_name}' received unknown slot(s): {names}. "
            f"Valid slots are: {valid}."
        )

    # Build result with defaults for missing optional slots
    result: dict[str, str] = {}
    for name, slot in declared_slots.items():
        if name in provided_slots:
            result[name] = provided_slots[name]
        elif slot.required:
            valid = ", ".join(sorted(declared_slots))
            raise ValueError(
                f"'{component_name}' requires slot '{name}' but it was not provided. "
                f"Declared slots: {valid}."
            )
        else:
            result[name] = slot.default

    return result

options: members: true show_root_heading: false show_source: true show_symbol_type_heading: true show_symbol_type_toc: true docstring_style: google merge_init_into_class: true