npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liiift-studio/sanity-nested-object-selector

v1.0.3

Published

Sanity Studio searchable checkbox selector for nested objects within Sanity documents.

Readme

sanity-nested-object-selector

npm version license

Sanity Studio searchable checkbox selector for items nested within another document type. Builds GROQ queries dynamically and supports a title filter, single-click selection, and selection count feedback.

Use it when an editor needs to multi-select values that live inside the array of some other document — for example, picking specific products out of every category document, or sections out of every licenseGroup — without hand-writing a custom input per field. Point it at the source document type and the nested array via schema options; it fetches, flattens, and deduplicates the candidates for you, and stores the chosen values as a plain string[].

How it works

The component reads its configuration from the field's schema options, runs a generated GROQ query against your dataset, flattens the nested arrays from every matching document into { title, value } items (deduplicated by value), and renders them as a checkbox list. The values you tick are written back to the field as a string[].

Data flow: source documents are projected and flattened into deduplicated title/value items, rendered as a checkbox selector, and stored as a string array of the selected values.

Screenshot wanted. This is a Studio UI component and cannot be captured headlessly. A maintainer screenshot/GIF of the selector in the Studio (search box + checked rows + "N selected" footer) should be added here. Placeholder — see assets/.

Install

npm install @liiift-studio/sanity-nested-object-selector

Usage

Use NestedObjectArraySelector as a custom input component on an array field:

import { NestedObjectArraySelector } from '@liiift-studio/sanity-nested-object-selector'

export const mySchema = defineType({
	name: 'collection',
	type: 'document',
	fields: [
		defineField({
			name: 'products',
			title: 'Products',
			type: 'array',
			of: [{ type: 'string' }],
			components: {
				input: NestedObjectArraySelector,
			},
			options: {
				sourceType: 'category',          // Document type that contains the nested array
				nestedField: 'products',         // Array field name within sourceType
				titleField: 'name',              // GROQ expression for the display label
				valueField: 'slug.current',      // GROQ expression for the stored value
				filter: 'status == "active"',    // Optional GROQ filter clause
				sortBy: 'name asc',              // Optional client-side sort (field + asc/desc)
				searchPlaceholder: 'Search products...',
				emptyMessage: 'No products found',
			},
		}),
	],
})

titleField and valueField are GROQ projection expressions evaluated in the scope of each nested item, so dotted paths like slug.current work. Each nested item must resolve to a non-empty title and value — items missing either are dropped. The stored field value is an array of the resolved value strings (e.g. ["oxford", "garamond"]); when nothing is selected the field is unset.

Options

| Option | Required | Description | |---|---|---| | sourceType | yes | Document _type to query. | | nestedField | yes | Name of the array field within sourceType to flatten. | | titleField | yes | GROQ expression (in nested-item scope) for the display label. | | valueField | yes | GROQ expression (in nested-item scope) for the stored value. | | filter | no | GROQ filter clause appended to the document query (e.g. status == "active"). | | sortBy | no | Client-side sort as "<field> <asc\|desc>". Defaults to title asc; non-title fields fall back to sorting by title. | | searchPlaceholder | no | Placeholder for the search box. | | emptyMessage | no | Message shown when the query returns no items. |

If any of the four required options is missing, the component renders a configuration-error card instead of the list.

The useNestedObjects hook

The data layer is also exported on its own, in case you want to render the items with your own UI:

import { useNestedObjects } from '@liiift-studio/sanity-nested-object-selector'

const { objects, loading, error } = useNestedObjects({
	sourceType: 'category',
	nestedField: 'products',
	titleField: 'name',
	valueField: 'slug.current',
	filter: 'status == "active"', // optional
	sortBy: 'name asc',           // optional
})
// objects is an array of { title: string, value: string }

It uses the Studio client (useClient, API version 2023-01-01), so it must be called inside a Sanity Studio React tree.

The package ships as compiled ESM/CJS without bundled .d.ts type declarations.

Features

  • Title-substring search box (appears once there are more than 5 items)
  • Single-click checkbox selection
  • Selected-count indicator
  • Dynamic GROQ query generation across a source document type
  • Automatic flattening and deduplication of nested items by value field

GROQ note

The sourceType, nestedField, titleField, valueField, filter, and sortBy values are interpolated directly into the generated GROQ query. They are intended to come from trusted schema configuration only — do not wire them to end-user input.

Requirements

This is a Sanity v3+ Studio plugin (built and tested against Sanity v5). It is a Studio input component, not a standalone library — it must run inside a Sanity Studio.

| Package | Version | |---|---| | @sanity/ui | >=3 | | react | >=18 | | sanity | >=3 |

License

MIT