Fragment

Specify the data requirements for a Svelte component.

<script lang="ts">
    import { fragment, graphql } from '$houdini'
    import type { UserAvatar } from '$houdini'

    export let user: UserAvatar
    $: data = fragment(user, graphql(`
        fragment UserAvatar on User {
            profilePicture
        }
    `))
</script>

<img src={$data.profilePicture} />
<script>
    import { fragment, graphql } from '$houdini'
    
    /* @type { import('$houdini').UserAvatar } */
    export let user
    $: data = fragment(user, graphql(`
        fragment UserAvatar on User {
            profilePicture
        }
    `))
</script>

<img src={$data.profilePicture} />

Inline Fragments

Inline fragments can defined using fragment imported from $houdini as shown above.

Inputs

  1. The prop containing the fragment reference (to be passed by another component that mixed in the fragment)
  2. A string tagged with graphql containing a single document with fragment

Return Values

fragment returns a store containing the fragment values. These values will be updated as query, mutations, and subscriptions get new values.

External Documents

Fragments stores can be created from your external documents by using the .get method on the store in $houdini:

<script lang="ts">
    import { UserAvatarStore } from '$houdini'
    import type { UserAvatar } from '$houdini'

    // the reference will get passed as a prop
    export let user: UserAvatar

    // load the the required UserAvatar for this component
    $: data = new UserAvatarStore().get(user)
</script>

<img src={$data.profilePicture} />
<script>
    import { UserAvatarStore } from '$houdini'
    
    // the reference will get passed as a prop
    /* @type { import('$houdini').UserAvatar } */
    export let user
    
    // load the the required UserAvatar for this component
    $: data = new UserAvatarStore().get(user)
</script>

<img src={$data.profilePicture} />

Fragment Arguments

In some situations it’s necessary to configure the documents inside of a fragment. For example, you might want to extend the UserAvatar component to allow for different sized profile pictures. To support this, houdini provides two directives @arguments and @with which declare arguments for a fragment and provide values, respectively.

Default values can be provided to fragment arguments with the default key:

fragment UserAvatar on User @arguments(width: { type: "Int", default: 50 }) {
	profilePicture(width: $width)
}

In order to mark an argument as required, pass the type with a ! at the end. If no value is provided, an error will be thrown when generating your runtime.

fragment UserAvatar on User @arguments(width: { type: "Int!" }) {
	profilePicture(width: $width)
}

Providing values for fragments is done with the @with decorator:

query AllUsers {
	users {
		...UserAvatar @with(width: 100)
	}
}

Keep in mind, if you are using fragment variables inside of a field flagged for list operations, you’ll have to pass a value for the variable when performing the operation

Paginated Fragments

Fragments may also contain a paginated field, similar to queries. A paginated fragment must use the paginatedFragment function and have a field tagged with the @paginate directive. For more information Houdini’s support for pagination, please visit the Pagination guide.

<script lang="ts">
    import { paginatedFragment, graphql } from '$houdini'
    import type { UserWithFriends } from '$houdini'

    export let user: UserWithFriends
    $: friendList = paginatedFragment(user, graphql(`
        fragment UserWithFriends on User {
            friends(first: 10) @paginate {
                name
            }
        }
    `))
</script>

<button on:click={() => friendsList.loadNextPage()}>
    load more
</button>

{#each $friendsList.data.friends.edges as { node }}
    <div>{node.name}</div>
{/each}
<script>
    import { paginatedFragment, graphql } from '$houdini'
    
    /* @type { import('$houdini').UserWithFriends } */
    export let user
    $: friendList = paginatedFragment(user, graphql(`
        fragment UserWithFriends on User {
            friends(first: 10) @paginate {
                name
            }
        }
    `))
</script>

<button on:click={() => friendsList.loadNextPage()}>
    load more
</button>

{#each $friendsList.data.friends.edges as { node }}
    <div>{node.name}</div>
{/each}

Return Values

paginatedFragment returns a store that holds an object with the following keys:

  • data contains the fragment’s data
  • loading contains a boolean value that tracks the loading state of the pagination requests
  • pageInfo ts contains the page info (hasPreviousPage, hasNextPage, etc.) Only valid for cursor-based pagination.
  • partial contains a boolean that indicates if the result has a partial match

The store also has one of the following methods (depending on your fields pagination direction):

  • loadNextPage is an async function that loads the next page. It takes one optional argument: the page size to load for the next request.
  • loadPreviousPage is an async function that loads the previous page. It takes one optional argument: the page size to load for the next request.

Fragment masking

By default fields from a fragment are not included in a query to encourage separation of concerns. You can override this default behavior with the config option defaultFragmentMasking: "disable" for all fragment usages or individually per fragment:

query CurrentUser {
	me {
		uuid
		...UserProfile @mask_disable
		...UserMeta
	}
}

With this directive in place (and the default of masking fragment fields) you can access all fields from the UserProfile fragment directly on the me object together with uuid. All fields from UserMeta stay masked (without changing the default behavior).

This individual setting works not recursive except for the usages of fragments inside UserProfile that also have this directive.