Theme
Version
GitHub PyPI Discord
On this page

Built-in tags

Look up a built-in <c-*> tag here: what it does, its attributes, and a short example. Every component template can use these tags without registering or importing anything.

Control flow

<c-if>

Render a block only when its cond expression is truthy. Any number of <c-elif> branches and one <c-else> may follow it.

<c-if cond="is_admin">
  <p>Administrator tools</p>
</c-if>

Conditions and loops covers the inline c-if attribute, truthiness, and branch order.

<c-elif>

Add another condition to a <c-if> chain. The branch renders when every earlier condition was false and its own cond is truthy.

<c-if cond="is_admin">Admin</c-if>
<c-elif cond="is_editor">Editor</c-elif>

<c-else>

Add the final fallback to a <c-if> chain. It takes no cond.

<c-if cond="is_signed_in">Account</c-if>
<c-else>Sign in</c-else>

<c-for>

Repeat a block for every item in an iterable. The each attribute is written like a Python for: a target, in, and an expression.

<c-for each="book in books">
  <p>{{ book.title }}</p>
</c-for>

Conditions and loops covers unpacking, filtering, and variable scope.

<c-empty>

Show an empty state when the <c-for> right before it has no items.

<c-for each="book in books">
  <p>{{ book.title }}</p>
</c-for>
<c-empty>No books yet.</c-empty>

Slots

<c-slot>

Mark a place in a component where the template that uses it can add content. Leave out name for the default slot, and name each extra slot. Content inside the tag is shown when no content is passed.

<article>
  <c-slot />
  <footer>
    <c-slot name="footer">No footer supplied.</c-slot>
  </footer>
</article>

Slots covers required slots, slot data, dynamic names, and fallback content.

<c-fill>

Send a block of content to a named slot of the component you are using. For the default slot alone, put the content directly in the component's body instead.

<c-Panel>
  <c-fill name="footer">
    <a href="/help/">Get help</a>
  </c-fill>
</c-Panel>

Dynamic output

<c-component> built-in component

Render the component named by is in this tag's place.

is (required) is a registered component name or a Component class; every other attribute is passed to it as a kwarg, and the body (fills included) as its slots.

<c-component is="card" />
<c-component c-is="chosen_component" />

<c-element> built-in component

Render a plain HTML element whose tag name is the is value.

is (required) is the tag name; every other attribute becomes an HTML attribute of the element, and the body its children. Void elements (br, img, ...) reject a body.

<c-element c-is="tag" class="heading">
  {{ text }}
</c-element>

Dynamic components has complete examples and explains how component names differ from HTML tag names.

Data and resilience

<c-provide> built-in component

Provide data to the components rendered inside this tag.

key (required) names the data; all other attributes become the provided fields, injectable below as self.inject(key).<field>.

<c-provide key="theme" name="dark">
  <c-theme-label />
</c-provide>

Provide and inject shows how a component reads the value.

<c-cache> built-in component

Save the HTML of the wrapped part of a template and reuse it on later renders.

key (required) names the cached part. Templates that use the same key share saved HTML, so list in vary every value that can change the output, such as the user id or the locale: each combination gets its own saved copy. ttl is how many seconds a copy stays saved (by default, the app's cache setting); with None it never expires, and 0 turns caching off. Change version to stop reusing the copies saved under the old value, for example after you change what the wrapped part shows. enabled=False also turns caching off. Citry does not look at the wrapped content when it builds the key, and the tag adds no HTML of its own.

<c-cache
  key="account-menu"
  c-vary="[current_user.id, locale]"
  c-ttl="300"
>
  <c-account-menu
    c-user="current_user"
    c-locale="locale"
  />
</c-cache>

Caching covers keys, expiry, and clearing entries.

<c-error-fallback> built-in component

Catch render errors in the wrapped content and show fallback content instead.

The guarded content is the tag body (the default slot). The fallback is the fallback attribute (a string), or the fallback fill, which receives the error as slot data (data.error). Ordinary fallback strings are escaped; use the fill when the fallback needs markup.

<c-error-fallback fallback="Recent activity is unavailable">
  <c-recent-activity />
</c-error-fallback>

Error boundaries shows a fallback with markup and nested boundaries.

Targeted updates

<c-mark> built-in component

Name part of a component's template so an event handler can update only that part.

name (required) is case-sensitive, starts with a letter, and contains only letters, digits, hyphens, and underscores. The tag accepts no other attribute and only its default slot.

Each name may render only once per component: a <c-mark> inside a <c-for> that loops over more than one item, or two tags with the same name that both render, raise ValueError when the component renders. Tags in different <c-if>/<c-else> branches may share a name, because only one of them renders. A <c-mark> written inside a <c-fill> belongs to the component whose template holds the fill, and one in a simple=True component's template belongs to the component that calls it.

To update the marked part, return actions.Render(..., target="mark:<name>") from an event handler:

<c-mark name="summary">
  <c-CartSummary c-cart="cart" />
</c-mark>

Write name as a plain attribute. A computed c-name, or a name that breaks the rules above, raises ValueError when the component renders. <c-mark> takes no <c-fill>; put the content directly inside it.

See <c-mark> partial update.

You cannot name a component mark

A component class named Mark, or one registered as mark, fails when it is defined:

AlreadyRegistered: Cannot register 'Mark' as 'mark': the name is
reserved for the built-in <c-mark> component.

Rename the class, for example to Highlight, and write <c-highlight> in your templates.

Internationalization

<c-i18n> built-in component

Set the locale for the content inside this tag.

locale, direction ("ltr" or "rtl"), time_zone, and context (a whole locale context) override the inherited values. Add tag to wrap the content in that HTML element with lang and dir set from the locale. The client attribute, which sends the locale to browser code, requires tag, and so does a <c-i18n> placed inside a client one; without it the tag raises ValueError.

Use it to set the locale for one part of the page. Add tag when that part needs lang and dir attributes. To let browser code in that part translate and format text, add the bare client attribute as well:

<c-i18n locale="ar-EG" tag="aside">
  <c-account-card />
</c-i18n>

See Locales and context and Browser i18n.

<c-trans> built-in component

Render a translated message that contains HTML, such as a link or a component.

message (required) is the message id. values maps the message's variables to values, and each <c-fill> supplies the HTML for the placeholder with the same name, so the translator decides where the link goes. attr picks one attribute of the message instead of its main text. Citry escapes the translated text itself. Using one name both in values and as a fill, or passing any other attribute, raises ValueError.

Use it when a translated sentence contains a link or a component, and the translator decides where it goes:

<c-trans
  message="my-app-terms-acceptance"
  c-values="{'account_name': account.name}"
>
  <c-fill name="terms_link">
    <a href="/terms">{{ tr("my-app-terms-name") }}</a>
  </c-fill>
</c-trans>

See Rich messages.

Page assets

<c-css> built-in component

Mark where Citry puts the stylesheet tags for the page's components.

Without it, the stylesheets go at the end of <head>. Passing an attribute or a body raises ValueError. When a page has several, the first one gets the stylesheets and the others render nothing.

<c-js> built-in component

Mark where Citry puts the <script> tags for the page's components.

Without it, the scripts go at the end of <body>. Passing an attribute or a body raises ValueError. When a page has several, the first one gets the scripts and the others render nothing.

Without them, Citry puts the CSS at the end of <head> and the JavaScript at the end of <body>. Use the tags to place them somewhere else, such as before your own stylesheet:

<head>
  <c-css />
  <link rel="stylesheet" href="/static/overrides.css">
</head>
<body>
  <c-Chart c-points="[1, 2, 3]" />
  <c-js />
</body>

Asset placement explains where Citry puts the collected files and component assets.

Literal template text

<c-raw>

Keep text that looks like template syntax exactly as written. Citry does not evaluate expressions or component tags inside <c-raw>.

<c-raw>
  {{ this_stays_as_text }}
  <c-Card>This tag stays as text too.</c-Card>
</c-raw>

Literal text covers what is trusted and the exact rules.

Reserved names

You cannot give a component the name of a built-in tag (if, slot, cache, mark and the others above). Four more names are kept for built-in tags Citry plans to add: lazy, teleport, transition and suspense. A component class named Teleport, or one registered as teleport, fails when it is defined or registered:

AlreadyRegistered: Cannot register 'Teleport' as 'teleport': the name
is reserved for a future built-in <c-teleport> tag.

Rename the class, for example to TeleportTarget. A longer name that contains a reserved word, such as LazyCard, is allowed.