Auto-populate fields from API: Document action vs inline button like slug generator
You're on the right track! Document actions aren't the best fit for this use case since they're designed for document-level operations in a dropdown menu. What you actually want is a custom input component with a button right next to the field, similar to how the slug generator works.
The Form Components API is exactly what you need. You can create a custom input component that includes a button positioned near your field to trigger the API call and populate other fields.
Here's a practical example of how to implement this:
import { StringInputProps, set, useFormValue } from 'sanity'
import { Button, Stack, TextInput } from '@sanity/ui'
import { useState } from 'react'
export function ItemNumberInput(props: StringInputProps) {
const { onChange, value, elementProps } = props
const [loading, setLoading] = useState(false)
const handleFetch = async () => {
if (!value) return
setLoading(true)
try {
const response = await fetch(`https://your-api.com/items/${value}`)
const data = await response.json()
// Populate multiple fields using onChange with paths
onChange([
set(value), // Keep current field value
set(data.title, ['title']), // Populate title field
set(data.description, ['description']), // Populate description
set(data.category, ['category']), // Add more fields as needed
])
} catch (error) {
console.error('Failed to fetch item data:', error)
} finally {
setLoading(false)
}
}
return (
<Stack space={3}>
<TextInput
{...elementProps}
value={value || ''}
onChange={(event) => onChange(set(event.currentTarget.value))}
/>
<Button
text="Fetch Item Details"
onClick={handleFetch}
disabled={!value || loading}
tone="primary"
/>
</Stack>
)
}Then in your schema:
defineField({
name: 'itemNumber',
type: 'string',
title: 'Item Number',
components: {
input: ItemNumberInput
}
})Key advantages of this approach:
- Better UX - The button appears right where editors need it, next to the input field (just like the slug generator)
- Real-time updates - Uses Sanity's patch system to update fields immediately
- Access to document context - You can read other field values using
useFormValue()if needed - Conditional logic - Easy to disable the button when the field is empty or show loading states
For more sophisticated implementations, check out these guides:
- Query APIs from your Custom Inputs - Shows exactly this pattern with a dropdown selector
- Form Components API docs - Complete reference for custom inputs
If you need to populate fields conditionally only if they're empty, you can use setIfMissing instead of set:
import { setIfMissing } from 'sanity'
onChange([
set(value),
setIfMissing(data.title, ['title']), // Only set if title is empty
])You can also access the entire document context if you need to make decisions based on other field values:
const document = useFormValue([]) as anyThis approach gives you much more control than document actions and creates exactly the UX pattern you're looking for - a button-triggered action right next to the field where editors are working!
Show original thread3 replies
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.