Skip to content

Fragment

There are two ways to use fragments in Houdini. The first is defining it inside of the useFragment hook and this approach will always work in all situations:

src/components/ShowCard.tsx
import { graphql, useFragment } from "$houdini";
export function ShowCard(props: { show: ShowCardInfo }) {
const data = useFragment(props.show, graphql(`
fragment ShowCardInfo on Show {
name
}
`))
return (
<div>
{data.name}
</div>
)
}

And then can be passed to your graphql query:

src/routes/show/[id]/+page.gql
query ShowInfo($id: ID!) {
show(id: $id) {
...ShowCardInfo
}
}

And then threaded through to the component:

src/routes/show/[id]/+page.tsx
import { ShowCard } from '...'
import type { PageProps } from './$types'
export default function ShowInfoView({ ShowInfo }:PageProps) {
return (
<ShowCard show={ShowInfo.show} />
)
}
src/routes/show/[id]/+page.jsx
import { ShowCard } from '...'
export default function ShowInfoView({ ShowInfo }) {
return (<ShowCard show={ShowInfo.show}/>)
}

Component Fields

When building reusable components, it is very common to find yourself repeatedly importing the same component and mixing in the same fragment over and over. This can get really tedious and so Houdini tries to address this by blurring the lines between your queries and your component library.

The idea is pretty simple on the surface: components can register themselves as fields on a type. But before we can use this feature, we need to enable the feature flag in houdini.config.js. Keep in mind this means that this API might change with any minor version. We understand this isn’t semantic versioning by the book but hopefully you understand.

houdini.config.js
export default {
// ...
features: {
componentFields: true
}
}

With that enabled, your components can define fragments using a slightly different API:

src/components/UserAvatar.tsx
import { GraphQL } from '$houdini'
type Props = {
user: GraphQL<`{
... on User @componentField(field: "Avatar") {
avatarURL
}
}`>
}
export default function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}
src/components/UserAvatar.jsx
import { graphql } from '$houdini'
graphql(`{
... on User @componentField(field: "Avatar", prop: "user") {
avatarURL
}
}`)
export default function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}

This example registers the Avatar field on the User type:

src/routes/profile/+page.gql
query Profile {
currentUser {
Avatar
}
}

Which can be used directly as a component in your page source. Notice there’s no need to import the component or remember the name of the prop that needs to be passed:

src/routes/profile/+page.tsx
import type { PageProps } from './$types'
export default function ShowInfoView({ Profile }: PageProps) {
return (
<div>
<Profile.currentUser.Avatar />
</div>
)
}
src/routes/profile/+page.jsx
export default function ShowInfoView({ Profile }) {
return (
<div>
<Profile.currentUser.Avatar />
</div>
)
}

Component Field Arguments

@componentField can be mixed with @arguments to define arguments on the field added for the component:

src/components/UserAvatar.tsx
import { GraphQL } from '$houdini'
type Props = {
user: GraphQL<`{
... on User
@componentField(field: "Avatar")
@arguments(size: { type: "Int" })
{
avatarURL(size: $size)
}
}`>
}
export default function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}
src/components/UserAvatar.jsx&javascriptExample=true
import { graphql } from '$houdini'
graphql(`{
... on User
@componentField(field: "Avatar")
@arguments(size: { type: "Int" })
{
avatarURL(size: $size)
}
}`)
export default function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}
src/routes/profile/+page.gql
query Profile {
currentUser {
Avatar(size: 150)
}
}

Named Exports

If your file exports the component by a specific name (instead of a default export) then you must tell houdini which export it should use:

src/components/UserAvatar.tsx
import { GraphQL } from '$houdini'
type Props = {
user: GraphQL<`{
... on User @componentField(field: "Avatar", export: "UserAvatar" ) {
avatarURL(size: $size)
}
}`>
}
export function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}
src/components/UserAvatar.jsx&javascriptExample=true
import { graphql } from '$houdini'
graphql(`{
... on User @componentField(field: "Avatar", export: "UserAvatar" ) {
avatarURL(size: $size)
}
}`)
export function UserAvatar({ user } : Props) {
return <img src={user.avatarURL} />
}