Theme
Version
GitHub PyPI Discord
On this page

Limits and errors

Something failed: the template does not load, the page shows an error, or a part of the page does nothing in the browser. This page lists the Vue features Citry does not support, then the common errors with their fixes. Each common error starts with what you see. When an error comes from the browser, start with Diagnose failures.

What is not supported

The Vue features in this section fail when the template loads, and the error says what to write instead. citry check and the editor report them too.

Vue built-in components

<Transition>, <TransitionGroup>, <KeepAlive>, <Teleport>, and <Suspense> fail on every page, in any spelling, such as <KeepAlive> or <keep-alive>. Use these instead:

Vue componentUse instead
<Transition>, <TransitionGroup>A CSS transition or animation, with the class changed by :class.
<KeepAlive>Leave the child rendered and hide it with v-show.
<Teleport>The HTML <dialog> element, the popover attribute, or Citry UI's <c-CDialog> and <c-CPopover>.
<Suspense>A loading flag in the component's data, with v-if and v-else.

v-once and v-memo

Both fail on elements and component tags alike. To compute a fixed value once, do it in data(). To keep an element's contents as the server first rendered them, use #c-ignore.

Alpine modifiers

.outside, .window, .document, .debounce, and .throttle are Alpine modifiers. Citry 0.6.0 moved from Alpine to Vue, which has none of these modifiers, so Citry rejects them on a Vue listener, and the error says how to write the same behavior in Vue:

{# Fails: .outside is an Alpine modifier #}
<div @click.outside="open = false;">...</div>

For a click outside, listen for click on document in mounted(), skip clicks inside the component, and remove the listener in unmounted():

$component({
  data() {
    return { open: false };
  },
  methods: {
    closeOnOutsideClick(event) {
      // A click inside the component keeps it open.
      if (!this.$refs.root?.contains(event.target)) {
        this.open = false;
      }
    },
  },
  mounted() {
    document.addEventListener("click", this.closeOnOutsideClick);
  },
  unmounted() {
    document.removeEventListener("click", this.closeOnOutsideClick);
  },
});

Mark the element that counts as inside with ref="root" in the template.

To call a Python event handler, use an @c-* attribute: it accepts .debounce and .throttle; see Bind events in templates. The 0.6.0 upgrade guide covers the rest of the move from Alpine.

Common errors

Each entry below is short. Follow its link for the full explanation.

A Python name in Vue

A Vue attribute that reads a Python name sets nothing, such as :title="item" inside a c-for loop. A Vue expression runs in the browser and cannot see Python names; citry check and the editor report it. Set the attribute from Python with c-title, or send the value to the browser with js_data(). See Tell Python from Vue.

Unknown directive

A template uses a custom directive, such as v-tooltip, that nothing registers. The page's Vue app stops, and the browser console shows an error that names the directive and the component.

Check the spelling, or register the directive: in the directives option of the component's $component({...}), as in v-show on a child, or for every component with a Vue plugin.

Key names on clicks

@click.enter fails when the template loads. Citry accepts a key name such as .enter or .escape only on keydown, keyup, and keypress, because other events have no key and Vue would run the listener on every event. Listen to keydown or keyup instead, as in @keydown.enter. See Vue v-* directives for the full rule, which covers @c-* attributes too.

Name clashes

The component fails with an error that names a value. Two cases cause it:

  • a js_data() key reuses a name from data(), setup(), props, injections, methods, or computed values;
  • the component defines a name that Citry adds to every component, such as $loading.

Rename your value. See Reserved names.

v-show needs one root

v-show or a custom directive on a component tag, such as <c-Panel v-show="open">, needs the child's template to render exactly one root element, because Vue applies the directive to that element. Otherwise the render fails with an error naming the directive and the child. That happens when the child's template has:

  • several top-level elements, or an element next to text;
  • a top-level v-for, <c-for>, or <c-slot>;
  • only text;
  • top-level HTML from Python, such as <c-raw>.

When the child's root is another component with such a template, the browser reports the error instead.

Wrap the child's template in one element, or put the directive on an element around the child tag:

<div v-show="open">
  <c-Panel />
</div>

Directive spelling

V-IF and v-If fail when the template loads. Write the v- prefix and Vue's own directive names in lowercase. Names that start with v-c- or v-citry- fail too, because Citry keeps them for its own use. See Vue v-* directives.

Vue on built-in tags

<c-element is="div"> renders a plain HTML element, so every Vue directive works on it. When Python picks the tag with c-is, : bindings and @ listeners still work, but a v- directive such as v-if or v-show makes the render fail with an error that names it. Put the directive on an element around the <c-element>.

A built-in tag that renders only its content, such as <c-provide>, accepts no Vue syntax. The render fails, and the error says to put the binding on an element inside the tag.

<c-slot> accepts no Vue syntax either; see v-if around a slot.

<template #name> in a component tag

<c-Panel><template #title>...</template></c-Panel> fails when the template loads. Fill a Citry component's slot with <c-fill name="title">. See <template #name> slots.

Vue code in c-bind

Rendering the template raises citry.VueCodeError, and the error names an attribute such as '@click'. A Vue directive, : binding, or @ listener came from c-bind, or was written with a c- prefix such as c-v-if. This happens on every page, even one that does not use Vue. Write it directly in the template. See No Vue code in c-bind.

Diagnose failures

When a page fails in the browser, start with the first [Citry] error in the browser console. Later errors are often caused by the first one. Citry writes the page's content inside one element, the Vue host, where Vue starts. Common causes:

  • a fragment or asset that did not load completely;
  • a Vue host or configuration script that an optimizer changed or removed; see Preserve page HTML;
  • component data from the server that the runtime rejects;
  • browser code that moved or removed elements inside the Vue host.

Troubleshooting covers the wider server and browser investigation.

See also