Expose a method from a component

Use the <method> element to export imperative actions and state accessors from a user-defined component.

A ModalTracker component wraps a modal dialog and privately tracks how many times it has been opened. The parent has no direct access to that counter — it lives entirely inside the component. Two exported methods bridge the gap: open() increments the counter and opens the dialog, while getOpenCount() returns the current count so the parent can display it.

<App var.openCount="{0}">
  <HStack>
    <Button
      label="Open Modal"
      onClick="{
        tracker.open();
        openCount = tracker.getOpenCount();
      }"
    />
    <Text>Opened { openCount } time(s)</Text>
  </HStack>
  <ModalTracker id="tracker" title="Task Details" />
</App>
<Component name="ModalTracker" var.openCount="{0}">
  <ModalDialog id="internalModal" title="{$props.title ?? 'Details'}">
    <VStack>
      <Text>This dialog has been opened { openCount } time(s) in total.</Text>
      <Button label="Close" onClick="internalModal.close()" />
    </VStack>
  </ModalDialog>

  <method name="open">
    openCount++;
    internalModal.open();
  </method>

  <method name="getOpenCount">
    return openCount;
  </method>
</Component>
Modal that tracks and exposes its open count
<App var.openCount="{0}">
  <HStack>
    <Button
      label="Open Modal"
      onClick="{
        tracker.open();
        openCount = tracker.getOpenCount();
      }"
    />
    <Text>Opened { openCount } time(s)</Text>
  </HStack>
  <ModalTracker id="tracker" title="Task Details" />
</App>
<Component name="ModalTracker" var.openCount="{0}">
  <ModalDialog id="internalModal" title="{$props.title ?? 'Details'}">
    <VStack>
      <Text>This dialog has been opened { openCount } time(s) in total.</Text>
      <Button label="Close" onClick="internalModal.close()" />
    </VStack>
  </ModalDialog>

  <method name="open">
    openCount++;
    internalModal.open();
  </method>

  <method name="getOpenCount">
    return openCount;
  </method>
</Component>

Key points

Declaring a method: Add a <method name="…"> element anywhere inside the <Component> definition. The body is plain JavaScript — it can read and write local variables, call other components' APIs via their id, and return values:

<Component name="ModalTracker" var.openCount="{0}">
  <ModalDialog id="internalModal" title="Details"></ModalDialog>

  <method name="open">
    openCount++;          <!-- write internal state -->
    internalModal.open(); <!-- call a built-in component API -->
  </method>

  <method name="getOpenCount">
    return openCount;     <!-- expose internal state as a return value -->
  </method>
</Component>

Calling a method from the parent: Give the component an id and call the method like a regular function. The id registers a reference that built-in parent elements can use — it is not a $props value inside the component:

<Button onClick="tracker.open()" />
<ModalTracker id="tracker" />

Reading the return value: Assign the method call to a parent variable in the same event handler:

<App var.openCount="{0}">
  <Button onClick="{
    tracker.open();
    openCount = tracker.getOpenCount();
  }" />
  <Text>Opened { openCount } time(s)</Text>
  <ModalTracker id="tracker" />
</App>

<method> vs method. — same semantics, different syntax: Both forms register a named method on the component. method. is the compact attribute shorthand suited to a single expression; <method> is the element form that handles multi-line bodies more readably. Use whichever reads more clearly (see Delegate a method):

<!-- element form — clear when the body spans multiple lines -->
<Component name="ModalTracker" var.openCount="{0}">
  <method name="open">
    openCount++;
    internalModal.open();
  </method>
</Component>

<!-- attribute shorthand — equally valid for a one-liner -->
<Component name="ModalTracker" var.openCount="{0}"
  method.open="{ openCount++; internalModal.open(); }"
>

Internal state stays private: The openCount variable is local to ModalTracker. The parent cannot read or write it directly — it can only access it through getOpenCount(). This encapsulation is intentional: internal state can be refactored freely without changing the caller's code.