Build with Sanity MCP in Replit. Prizes up for grabs! Submit by June 14

Update field in another document when toggling boolean in Sanity schema

12 repliesLast updated: Dec 1, 2025

Hello Everyone! I have a question. How can i update a field value of another document when clic over a boolean type? I have the following schema:
export default {
    name:"myschema",
    type:"document",
    title:"My Schema",
    description:"MySchema",
    fields:[
        {
            name:"active",
            title:"Active",
            type:"boolean"
        },
        {
            name:"name",
            title:"Event Name",
            type:"string"
        }
    ] 
}
The idea is that only one document can have the active field as true without the editor having to manually unchecked the previous selected event.
AI Update

Hey there! Great question about implementing a "radio button" style behavior for boolean fields across documents. You want only one document to have active: true at a time, with the others automatically set to false when a new one is selected.

The best approach is to create a custom input component for your boolean field that automatically updates other documents when toggled. Here's how to implement it:

Custom Input Component Approach

Create a custom input component that uses the Sanity client to update other documents when the boolean is toggled:

// components/ExclusiveBooleanInput.tsx
import {BooleanInputProps, set, unset} from 'sanity'
import {Switch, Stack, Text} from '@sanity/ui'
import {useCallback} from 'react'
import {useClient} from 'sanity'

export function ExclusiveBooleanInput(props: BooleanInputProps) {
  const {value, onChange} = props
  const client = useClient({apiVersion: '2024-01-01'})

  const handleChange = useCallback(
    async (event: React.ChangeEvent<HTMLInputElement>) => {
      const newValue = event.target.checked

      // If setting to true, deactivate all other documents
      if (newValue) {
        try {
          // Find all other documents where active is true
          const activeDocuments = await client.fetch(
            `*[_type == "myschema" && active == true && _id != $currentId]._id`,
            {currentId: props.id}
          )

          // Create a transaction to update all active documents
          if (activeDocuments.length > 0) {
            const transaction = client.transaction()
            activeDocuments.forEach((docId: string) => {
              transaction.patch(docId, {set: {active: false}})
            })
            await transaction.commit()
          }
        } catch (error) {
          console.error('Error deactivating other documents:', error)
        }
      }

      // Update the current document's value
      onChange(newValue ? set(newValue) : unset())
    },
    [client, onChange, props.id]
  )

  return (
    <Stack space={3}>
      <Switch
        checked={value || false}
        onChange={handleChange}
      />
      {value && (
        <Text size={1} muted>
          This is the active event. Enabling another will deactivate this one.
        </Text>
      )}
    </Stack>
  )
}

Then register it in your schema:

// schemas/myschema.ts
import {ExclusiveBooleanInput} from '../components/ExclusiveBooleanInput'

export default {
  name: 'myschema',
  type: 'document',
  title: 'My Schema',
  description: 'MySchema',
  fields: [
    {
      name: 'active',
      title: 'Active',
      type: 'boolean',
      components: {
        input: ExclusiveBooleanInput
      }
    },
    {
      name: 'name',
      title: 'Event Name',
      type: 'string'
    }
  ]
}

How It Works

This approach follows the patterns described in the Custom Input Components documentation, where custom components receive props like value, onChange, and access to the document id through the props object.

Important Considerations

Alternative: Validation Rule

If you want a simpler approach that doesn't auto-update but prevents mistakes, you could add a custom validation rule that checks if another document is already active:

{
  name: 'active',
  title: 'Active',
  type: 'boolean',
  validation: Rule => Rule.custom(async (value, context) => {
    if (!value) return true // If false, no validation needed
    
    const {document, getClient} = context
    const client = getClient({apiVersion: '2024-01-01'})
    
    const otherActive = await client.fetch(
      `count(*[_type == "myschema" && active == true && _id != $id])`,
      {id: document._id}
    )
    
    return otherActive > 0 
      ? 'Another event is already active. Please deactivate it first.' 
      : true
  })
}

The custom input component approach gives the best user experience since it handles everything automatically for your editors!

Show original thread
12 replies

Was this answer helpful?

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.

Related contributions