Setting up a list view with conditional fields in Sanity.io.

35 replies
Last updated: Jun 4, 2020
can someone help me set up a list view?
it might be a little tricky because it involves the Conditional Fields custom component. I'll explain in the thread.
AI Update

I'd be happy to help you set up a list view with Conditional Fields! This is definitely doable, though it requires understanding how the Structure Builder and Conditional Fields work together.

Let me give you a comprehensive answer covering the most common scenarios:

Setting Up a Custom List View

First, you'll want to configure a custom structure in your sanity.config.ts:

import {structureTool} from 'sanity/structure'
import {structure} from './structure'

export default defineConfig({
  // ... other config
  plugins: [
    structureTool({structure}),
    // ... other plugins
  ],
})

Then create your structure file (e.g., structure/index.ts):

import type {StructureResolver} from 'sanity/structure'

export const structure: StructureResolver = (S) =>
  S.list()
    .id('root')
    .title('Content')
    .items([
      S.documentTypeListItem('yourDocType').title('Your Documents'),
      // Add more list items as needed
    ])

Conditional Fields in Your Schema

The Conditional Fields feature uses callback functions in your schema to show/hide fields based on document values:

{
  name: 'contentType',
  type: 'string',
  options: {
    list: ['image', 'video', 'text']
  }
},
{
  name: 'imageField',
  type: 'image',
  hidden: ({parent}) => parent?.contentType !== 'image'
},
{
  name: 'videoField',
  type: 'url',
  hidden: ({parent}) => parent?.contentType !== 'video'
}

Combining List Views with Conditional Fields

If you need to filter your list view based on documents that have certain conditional field configurations, you can use filtered document lists:

S.listItem()
  .title('Documents with Images')
  .child(
    S.documentList()
      .title('Image Content')
      .filter('_type == "yourDocType" && contentType == "image"')
  )

Common Challenges

Validation with Hidden Fields: If you have required fields that are conditionally hidden, you'll need conditional validation:

validation: (Rule) =>
  Rule.custom((currentValue, {parent}) => {
    return parent?.contentType === 'image' && !currentValue
      ? 'Image is required when content type is image'
      : true
  })

Arrays with Conditional Fields: When working with arrays of objects with conditional fields, the parent parameter in your callback refers to the array item object, not the document.

Feel free to share more details about your specific setup in your follow-up, and I can provide more targeted guidance!

I have document type of
moment

Here you choose from a
string
list of either
imageType
or
videoType

i'd like to use the preview subtitle to show which type a
moment
is.
then to go one deeper ... if you select
imageType
you have 4 choices of
displaySize

i'd like to use the description preview to show the
displaySize

so far, dot.notation has not worked to access either the type or the displaySize

thoughts?
Hi User, could you share the schema for
moment
?
happy to
Hi User, could you share the schema for
moment
?
import Gift from 'react-icons/lib/go/ruby'

export default {
  title: "Moment",
  name: "moment",
  icon: Gift,
  type: "document",
  fieldsets: [
    {
      title: "Tags",
      name: "tags",
      options: {
        collapsible: true,
        collapsed: false
      }
    }
  ],
  fields: [
    {
      title: "Title",
      name: "title",
      type: "string"
    },
    {
      name: "choice",
      type: "momentChoice"
    },
  ],
  preview: {
    select: {
      title: 'title',
      momentType: 'momentChoice.momentType'
    }
  }
}
happy to
i've stripped that down to the relevant fields
as i'm reading the documentation again, i'm thinking i'll need to use the
prepare
option, as i don't think simple dot.notation is going to cut it
I have document type of
moment

Here you choose from a
string
list of either
imageType
or
videoType

i'd like to use the preview subtitle to show which type a
moment
is.
then to go one deeper ... if you select
imageType
you have 4 choices of
displaySize

i'd like to use the description preview to show the
displaySize

so far, dot.notation has not worked to access either the type or the displaySize

thoughts?
ok, i have the first item working now (was incorrectly asking for
momentChoice
which is the type, not the name
asking for just
choice
gave me that
Indeed,
choice
(or
choice.name
if you were to have a name field inside the
momentChoice
object) should work in this case. For the second part, where does
displaySize
sit in this case? Inside
momentChoice
as a conditional field? What type if so?
You should be able to pass something like
displaySize: 'choice.displaySize'
to
select
for use in
prepare
, then check whether
displaySize
is set and, if so, use
subtitle: displaySize
there.
user M
inside
momentChoice
is the first conditional which segments
imageType
and
videoType

inside
imageType
is where
displaySize
is
Should be possible! Could you share that schema too? 😄
here is the
momentChoice
schema

export default {
  title: "Moment Choice",
  name: "momentChoice",
  type: "object",
  fields: [
    {
      name: "momentType",
      type: "string",
      description: "Choose moment type",
      options: {
        list: [
          { title: "Image", value: "imageType" },
          { title: "Video", value: "videoType" },
        ],
        layout: "radio",
        direction: "horizontal"
      }
    },
    {
      name: "imageType",
      type: "imageMoment",
      inputComponent: ConditionalFields,
      options: {
        condition: (document, context) => context().momentType === "imageType"
      }
    },
    {
      name: "videoType",
      type: "videoMoment",
      inputComponent: ConditionalFields,
      options: {
        condition: (document, context) => context().momentType === "videoType"
      }
    },
    {
      name: "textType",
      type: "textMoment",
      inputComponent: ConditionalFields,
      options: {
        condition: (document, context) => context().momentType === "textType"
      }
    }
  ]
}
and the
imageType
schema

export default {
  title: "Image Moment",
  name: "imageMoment",
  type: "object",
  fields: [
    {
      title: "Display Size",
      name: "displaySize",
      description: 'Preferred layout crop, only select if different from default',
      type: 'string',
      options: {
        list: [
          {title: 'Small Square', value: 'smSq'},
          {title: 'Big Square', value: 'bigSq'},
          {title: 'Vertical', value: 'vertical'},
          {title: 'Horizontal', value: 'horizontal'}
        ],
        layout: 'radio',
        direction: 'horizontal'
      }
    },
You’ll probably need to perform some checks in
prepare
and this won’t work yet, but for fun, could you try adding something like this to
select
?
subtitle: 'choice.imageType.displaySize.title'
yeah, no luck with that.
also tried
subtitle: 'choice.momentType.imageType.displaySize.title'
since it has to pass through momentChoice first
and yes, definitely aware that i'd have to check for it being an
imageType
at some point
Happy to experiment for a moment with this. Would you mind sending a zip of your schema files in DM? 🙂
absolutely
do you want all the schemas? or just the relevant ones?
Just the relevant ones is OK but please include the conditionalFields component just in case - they tend to be different on a case by case basis.
i included the ConditionalFields component as well
but i haven't modified it
thanks
user M
!
also, just realizing i have some poor file naming ... i have
momentChoice
as
MomentType.js
Hi again User - this should work 🤞
preview: {
  select: {
    title: 'title',
    subtitle: 'choice.momentType',
    description: 'choice.imageType.displaySize'
  }
}
that works!
i guess i was trying to over complicate it?
adding more levels than necessary 🤷‍♂️
When we think ‘nested’, it’s easy to go into let.me.nest.one.more.just.to.be.sure mode 😄
haha
so accurate 😂

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?