Watch a live product demo 👀 See how Sanity powers richer commerce experiences

React - How to Display a List of Schemas/Content Types but Only Allow the User to Select One

13 replies
Last updated: Jun 29, 2022
Hey 👋 Just a quick question, is it possible to display a list of schemas/content types but only allow the user to select one?
May 6, 2022, 3:32 PM
Like radio inputs somewhat?
May 6, 2022, 3:47 PM
Just made a quick example and attached a screenshot (ignore the names they make little sense 😆). Hoping to allow a user to select one, and only one, of the two options (in this example, Navigation Item or Link). I am just using an array type at the moment so can limit it to 1 using validation but this catches the errors after they’ve added too much content (they assume they did it by accident) which doesn’t seem great. Any help is super appreciated 😄
May 6, 2022, 3:56 PM
Ah! I see.
May 6, 2022, 3:57 PM
We have exactly the same thing at work and we solved it with a
.max(1)
validation rule.
May 6, 2022, 3:57 PM
It may seem annoying that you can effectively have several items in a draft, but it’s actually pretty handy for editors, rather than having to delete their item first before creating a new one.
May 6, 2022, 3:58 PM
And you ensure that a production document can’t have more than 1 with the validation rule. Win-win. 🙂
May 6, 2022, 3:58 PM
Yeh good points! Thanks for the quick reply 🙂. It would be cool to see how others have dealt with it
May 6, 2022, 4:02 PM
May 6, 2022, 5:11 PM
user A
has previously helped me with a custom array part which should do what you’re after! Once the array has the maximum number of items (set using
validation: (Rule) => Rule.max(x)
), the ‘Add item…’ button is removed:
May 6, 2022, 5:47 PM
Here’s the
LimitArray.js
part:
import React from "react";
import { isReferenceSchemaType } from "@sanity/types";
import { AddIcon } from "@sanity/icons";
import { Button, Grid, Menu, MenuButton, MenuItem } from "@sanity/ui";
import { useId } from "@reach/auto-id";

const LimitArray = React.forwardRef((props, ref) => {
    const { type, readOnly, children, onCreateValue, onAppendItem, value } = props;
    const menuButtonId = useId();
    const insertItem = React.useCallback(
        (itemType) => {
            const item = onCreateValue(itemType);
            onAppendItem(item);
        },
        [onCreateValue, onAppendItem]
    );
    const handleAddBtnClick = React.useCallback(() => {
        insertItem(type.of[0]);
    }, [type, insertItem]);
    if (readOnly) {
        return null;
    }
    const maxLength = type.validation[0]._rules.find((rule) => rule.flag === "max");
    if (maxLength && value && value.length >= maxLength.constraint) {
        return null;
    }
    return (
        <Grid
            gap={1}
            style={{ gridTemplateColumns: "repeat(auto-fit, minmax(100px, 1fr))" }}
            ref={ref}
        >
            {type.of.length === 1 ? (
                <Button icon={AddIcon} mode="ghost" onClick={handleAddBtnClick} text="Add item" />
            ) : (
                <MenuButton
                    button={<Button icon={AddIcon} mode="ghost" text="Add item…" />}
                    id={menuButtonId || ""}
                    menu={
                        <Menu>
                            {type.of.map((memberDef, i) => {
                                const referenceIcon =
                                    isReferenceSchemaType(memberDef) &&
                                    (<http://memberDef.to|memberDef.to> || []).length === 1 &amp;&amp;
                                    <http://memberDef.to[0].icon;|memberDef.to[0].icon;>
                                const icon =
                                    memberDef.icon || memberDef.type?.icon || referenceIcon;
                                return (
                                    &lt;MenuItem
                                        key={i}
                                        text={memberDef.title || memberDef.type?.name}
                                        onClick={() =&gt; insertItem(memberDef)}
                                        icon={icon}
                                    /&gt;
                                );
                            })}
                        &lt;/Menu&gt;
                    }
                /&gt;
            )}
            {children}
        &lt;/Grid&gt;
    );
});

export default LimitArray;
You need to add this file to your
parts
in your
sanity.json
as follows:
{
    "implements": "part:@sanity/form-builder/input/array/functions",
    "path": "./schemas/parts/LimitArray.js"
}
And then you can use this by setting
validation
on an array field:
{
    title: "Content",
    name: "content",
    type: "array",
    of: [{ type: "img" }, { type: "vid" }, { type: "word" }],
    validation: (Rule) =&gt; Rule.max(2),
},
May 6, 2022, 5:48 PM
Wow, thanks for sharing 👍
May 6, 2022, 6:45 PM
Just tried it and it works perfectly 👌 Thanks again!
May 6, 2022, 7:37 PM
2 months later, still coming in clutch. Thanks
user A
and
user P
Jun 29, 2022, 8:02 PM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Categorized in

Related answers

Get more help in the community Slack

TopicCategoriesFeaturedRepliesLast Updated
After adding the subtitle and running this code npm run graphql-deploy It does nothingSep 15, 2020
how to limit a reference to just one entry in Studio reference input side versus the default as-many-entries-as-you-fill-in-an-array...Sep 18, 2020
Is it possible to fetch more than one "_type" using GROQ?Nov 2, 2020
I want to add a view with the Structure builder (S.view.component) where I list similar documents based on the title. What...Sep 23, 2020
Is there a structure builder example where the format of each preview for the document list is modified?Feb 3, 2021
I have an array of references to a country schema type but it always just returns NULL values for meJan 30, 2021
Hi, I need help with a query for getting the url of an image asset. Here is what I've been trying, but I only get the _ref...Dec 1, 2020
Sanity UI looks brilliant :smiley: Is something like the current date picker possible at the moment? I’m not sure if anicon...Dec 21, 2020
Hey everyone. I have been coding and may have potentially accidentally deleted something. Does anyone know how to resolve...Dec 26, 2020
Hello everyone and happy new year :raised_hands::skin-tone-2:, I have a problem with outputting Portable Text :disappointed:...Jan 1, 2021

Related contributions

Clean Next.js + Sanity app
- Template

Official(made by Sanity team)

A clean example of Next.js with embedded Sanity ready for recomposition.

Cody Olsen
Go to Clean Next.js + Sanity app

Blog with Built-in Content Editing
- Template

Official(made by Sanity team)

A Sanity-powered blog with built-in content editing and instant previews.

Go to Blog with Built-in Content Editing