Create a reusable component

Extract repeated markup into a .xmlui file with properties and slots.

A project dashboard often renders the same task-card layout in several places — a My Tasks panel, an All Tasks panel, a sprint board, and so on. Copy-pasting the block is a fast start, but the copies quickly drift: one gets a status icon, another gets a wider priority badge, and soon you're maintaining four versions of the same thing. Extract the block into a single TaskCard component and every panel automatically benefits from any future change.

<App>
  <HStack wrapContent itemWidth="50%">
    <VStack>
      <H4>My Tasks</H4>
      <TaskCard
        title="Write release notes"
        priority="high"
        assignee="Alice"
        dueDate="2026-04-10"
      />
      <TaskCard
        title="Review pull request"
        priority="normal"
        assignee="Alice"
        dueDate="2026-04-12"
      />
    </VStack>
    <VStack>
      <H4>All Tasks</H4>
      <TaskCard
        title="Write release notes"
        priority="high"
        assignee="Alice"
        dueDate="2026-04-10"
      />
      <TaskCard
        title="Update dependencies"
        priority="low"
        assignee="Bob"
        dueDate="2026-04-15"
      />
      <TaskCard
        title="Fix login bug"
        priority="high"
        assignee="Carol"
        dueDate="2026-04-08"
      />
    </VStack>
  </HStack>
</App>
<Component name="TaskCard">
  <Card>
    <VStack>
      <Text variant="strong">{ $props.title ?? '(untitled)' }</Text>
      <HStack>
        <Badge
          value="{ $props.priority ?? 'normal' }"
          colorMap="{{
            high: '$color-warn',
            normal: '$color-success'
          }}"
        />
        <Text variant="secondary" fontSize="$fontSize-sm">{ $props.assignee }</Text>
      </HStack>
      <Text variant="secondary" fontSize="$fontSize-sm">Due: { $props.dueDate }</Text>
    </VStack>
  </Card>
</Component>
TaskCard used in two panels
<App>
  <HStack wrapContent itemWidth="50%">
    <VStack>
      <H4>My Tasks</H4>
      <TaskCard
        title="Write release notes"
        priority="high"
        assignee="Alice"
        dueDate="2026-04-10"
      />
      <TaskCard
        title="Review pull request"
        priority="normal"
        assignee="Alice"
        dueDate="2026-04-12"
      />
    </VStack>
    <VStack>
      <H4>All Tasks</H4>
      <TaskCard
        title="Write release notes"
        priority="high"
        assignee="Alice"
        dueDate="2026-04-10"
      />
      <TaskCard
        title="Update dependencies"
        priority="low"
        assignee="Bob"
        dueDate="2026-04-15"
      />
      <TaskCard
        title="Fix login bug"
        priority="high"
        assignee="Carol"
        dueDate="2026-04-08"
      />
    </VStack>
  </HStack>
</App>
<Component name="TaskCard">
  <Card>
    <VStack>
      <Text variant="strong">{ $props.title ?? '(untitled)' }</Text>
      <HStack>
        <Badge
          value="{ $props.priority ?? 'normal' }"
          colorMap="{{
            high: '$color-warn',
            normal: '$color-success'
          }}"
        />
        <Text variant="secondary" fontSize="$fontSize-sm">{ $props.assignee }</Text>
      </HStack>
      <Text variant="secondary" fontSize="$fontSize-sm">Due: { $props.dueDate }</Text>
    </VStack>
  </Card>
</Component>

Key points

File placement and naming: The file is components/TaskCard.xmlui. The name attribute on <Component> must match the filename exactly, and the name must start with an uppercase letter. XMLUI discovers files in the components/ folder automatically.

Accessing props with $props: Inside a user-defined component, every caller-supplied attribute is available through $props. There is no other way to read them:

<Component name="TaskCard">
  <Text>{ $props.title }</Text>   <!-- ✅ correct -->
  <Text>{ title }</Text>          <!-- ❌ title is not in scope -->
</Component>

Guard against missing props with ??: A caller may omit an optional attribute. The nullish-coalescing operator ?? provides a safe fallback without suppressing intentional false or 0 values:

{ $props.title ?? '(untitled)' }    <!-- falls back when title is absent -->
{ $props.priority ?? 'normal' }     <!-- falls back when priority is absent -->

Scope isolation: Variables or element IDs declared in the parent are invisible inside TaskCard. If the component needs a value from the parent, it must be passed explicitly as a prop:

<!-- parent -->
<App var.currentUser="Alice">
  <TaskCard assignee="{currentUser}" title="Fix bug" />
</App>

<!-- inside TaskCard: $props.assignee works, currentUser does not -->

id is reserved — never use it as a prop name: The id attribute is special in XMLUI: it registers a named reference that parent built-in components can use to call the component's API. If you pass id="{$item.id}" to a user-defined component, XMLUI captures it as the component reference, not as $props.id. Use a descriptive name instead:

<!-- ❌ wrong: id is captured by the framework, $props.id is undefined -->
<TaskCard id="{task.id}" />

<!-- ✅ correct: use a dedicated prop name -->
<TaskCard taskId="{task.id}" />

Why extract: Once TaskCard.xmlui exists, adding a status icon, changing the priority color, or tweaking padding is a one-file change that takes effect everywhere the component is used.