Skip to content

Fragments

Fragments are reusable UI components defined in XML. They are the primary building blocks of an XWidget application — each fragment describes a piece of your UI that XWidget inflates into Flutter widgets at runtime.

For the attribute value formats accepted by generated inflaters, see Attribute Values.

Defining a Fragment

Create XML files in your fragments directory (default: resources/fragments/):

<!-- resources/fragments/hello_world.xml -->
<Column xmlns="https://xwidget.dev/fragments">
    <Text data="Hello World">
        <TextStyle for="style" fontWeight="bold" color="#262626"/>
    </Text>
    <Text>Welcome to XWidget!</Text>
</Column>

Register the directory in pubspec.yaml:

flutter:
  assets:
    - resources/fragments/

Inflating Fragments in Dart

Use XWidget.inflateFragment() to inflate a fragment into the widget tree:

@override
Widget build(BuildContext context) {
  return XWidget.inflateFragment("hello_world", Dependencies());
}

The first argument is the fragment name (without the .xml extension). The second is the Dependencies instance that provides data for expression evaluation.

Fragment Name Resolution

Fragment names resolve to files in your fragments directory: "settings" finds settings/index.xml or settings.xml, and subdirectory paths like "auth/login" use forward slashes. The full resolution rules — and the pubspec.yaml asset registration every fragment directory needs — live in Resources.

Query Parameters

You can pass query parameters in the fragment name using standard URL syntax:

XWidget.inflateFragment("settings?tab=profile&edit=true", dependencies);

Query parameters are parsed and stored as dependencies, making them available to expressions within the fragment.

Nesting Fragments

Use the <fragment> tag to embed one fragment inside another:

<!-- resources/fragments/my_app.xml -->
<MaterialApp xmlns="https://xwidget.dev/fragments">
    <Scaffold for="home">
        <Column for="body">
            <fragment name="header"/>
            <fragment name="content"/>
            <fragment name="footer"/>
        </Column>
    </Scaffold>
</MaterialApp>

This lets you decompose complex UIs into smaller, reusable pieces. Each nested fragment is inflated independently and can have its own controller.

Fragment Tag Attributes

Attribute Required Description
name Yes Name of the fragment to render
for No Named slot in the parent widget to render into
visible No Controls whether the fragment is rendered (default: true)
dependenciesScope No How dependencies are passed to the fragment (see below)

The for Attribute

Use for to render a fragment into a named slot of the parent widget:

<AppBar>
    <fragment for="leading" name="profile/avatar"/>
</AppBar>

The visible Attribute

Conditionally show or hide a fragment:

<fragment name="admin_panel" visible="${isAdmin}"/>

When visible is false, the fragment is not inflated at all.

Inherited Attributes

Any attributes on the <fragment> tag that are not reserved (name, for, visible) are forwarded to the child fragment as inherited attributes:

<fragment name="user_card" userId="${user.id}" showAvatar="true"/>

These inherited attributes are available during inflation of the child fragment.

Passing Parameters

Use <param> child elements to pass named parameters to the fragment:

<fragment name="product_card">
    <param name="productId" value="${product.id}"/>
    <param name="showPrice" value="true"/>
</fragment>

Parameters are added to the fragment's dependencies before inflation.

Use XWidget.navigateToFragment() to navigate to a fragment as a new page:

XWidget.navigateToFragment(
  'screens/settings',
  dependencies,
  context: context,
  pageName: '/settings',
  params: {'userId': currentUser.id},
);
Parameter Required Description
fragmentName Yes Fragment to inflate as the new page
dependencies Yes Dependency scope for the fragment
context No Build context for locating the Navigator. If omitted, XWidget uses XRouter.navigatorKey.
pageName No Route name for RouteSettings (defaults to fragmentName)
params No Key-value pairs passed to the fragment
cupertinoStyle No Use iOS-style page transition (default: false)
removeUntil No RoutePredicate for removing routes beneath the new page
action No Navigator action to perform (default: NavigatorAction.push)

The pageName is used by the analytics system for navigation tracking. If you want analytics to show meaningful page names, set this explicitly.

Dependency Scoping

When a fragment is inflated, you can control how the parent's dependencies are shared using the dependenciesScope attribute:

Scope Behavior
inherit The fragment shares the parent's Dependencies instance (default)
copy The fragment gets a shallow copy — changes don't affect the parent
new The fragment gets a fresh, empty Dependencies instance
<!-- Children share the parent's dependencies -->
<fragment name="child_fragment" dependenciesScope="inherit"/>

<!-- Children get their own copy -->
<fragment name="child_fragment" dependenciesScope="copy"/>

<!-- Children start with a clean slate -->
<fragment name="child_fragment" dependenciesScope="new"/>

If dependenciesScope is omitted, the default depends on context. If the fragment has <param> children or query parameters in the name, the scope defaults to copy to avoid modifying the parent's dependencies. Otherwise, it defaults to inherit.

Variables

Use the <var> tag to set dependency values within a fragment:

<var name="greeting" value="Hello World"/>
<Text data="${greeting}"/>

The <var> tag supports the spread operator to merge a map into the current dependencies:

<var name="..." value="${userData}"/>

When a parent element contains <var> children and no explicit scope is set, XWidget automatically uses copy scoping to prevent the variables from leaking into the parent's dependencies.

XML Caching

XWidget caches parsed XML documents automatically to avoid re-parsing on subsequent inflations. The cache is managed by the active Resources instance; no configuration is required.

You rarely need to clear the cache manually — hot reload clears it automatically when a fragment file changes. If you update fragment content through some other mechanism (custom tooling, runtime content injection), clear it explicitly:

Resources.instance.clearFragmentCache();