OneOf Option for Single Entry Field

4 replies
Last updated: Jul 26, 2022
Hi all. I was just thinking of something: while an
array
field has an option
of
to list all possible types to insert (either embed or reference), AFAIK there's no equivalent for a single entry field. For example, type
object
with
oneOf
. Something like this would be very useful to have IMHO:
{
  type: 'object',
  name: 'thing',
  title: 'Thing',
  oneOf: [{ type: 'widget'}, { type: 'tool' }]
}
AI Update

I understand what you're looking for! Unfortunately, Sanity doesn't currently support a native oneOf property for single object fields like it does with the of property for arrays. This is indeed a limitation that comes up in the community.

However, there are a few workarounds you can use to achieve similar functionality:

1. Use an Array with maxLength: 1

The most straightforward approach is to use an array field with a maximum length of one item:

{
  type: 'array',
  name: 'thing',
  title: 'Thing',
  of: [
    { type: 'widget' },
    { type: 'tool' }
  ],
  validation: Rule => Rule.max(1).required()
}

This gives you the type selection UI you want, though it's technically an array. You'll need to access it as thing[0] in your queries and code.

2. Use Conditional Fields

You can create an object with a discriminator field that conditionally shows different fields based on the selection:

{
  type: 'object',
  name: 'thing',
  title: 'Thing',
  fields: [
    {
      name: 'type',
      type: 'string',
      options: {
        list: [
          { title: 'Widget', value: 'widget' },
          { title: 'Tool', value: 'tool' }
        ]
      }
    },
    {
      name: 'widgetData',
      type: 'widget',
      hidden: ({ parent }) => parent?.type !== 'widget'
    },
    {
      name: 'toolData',
      type: 'tool',
      hidden: ({ parent }) => parent?.type !== 'tool'
    }
  ]
}

This uses conditional fields to show/hide the appropriate fields based on the type selection. It's more verbose but gives you full control over the UX and creates a proper discriminated union pattern.

3. Use References

If your widget and tool are document types (rather than inline objects), you could use a reference field with multiple possible types:

{
  type: 'reference',
  name: 'thing',
  title: 'Thing',
  to: [
    { type: 'widget' },
    { type: 'tool' }
  ]
}

This is cleaner if your types are documents rather than inline objects.

Bottom Line

The lack of native union type support (like oneOf) for single object fields is a known limitation in Sanity schemas. The array-with-max-length approach is probably the closest to what you're envisioning, as it gives you the same type picker UI that arrays provide. The main tradeoff is handling it as an array in your queries and frontend code.

The conditional fields approach is more "proper" from a data modeling perspective since it creates an actual discriminated union, but requires more schema boilerplate. Choose based on whether you prefer simpler schema definition or cleaner data structure!

Like a union type. I would love this.
Maybe ideas-and-feedback? πŸ™‚
Will crosspost there πŸ™‚
You can use a selection of things though with an array and a validation of
maxLength
instead:
{
  type: 'array',
  name: 'thing',
  title: 'Thing',
  of: [{ type: 'widget'}, { type: 'tool' }],
  validation: Rule => Rule.max(1)
}
You can also use
options to do some awesome stuff btw.

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?