✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

Reference document browser input

By Karin

Visually browse the reference documents you want to select in a document.

schema.js

import ReferenceBrowser from '../path/to/reference-browser';

export default {
  name: "mySchema",
  title: "My Schema",
  type: "document",
  fields: [
    {
      title: 'References',
      name: 'references',
      type: 'array',
      options: { editModal: 'fullscreen' },
      of: [
        {
          type: 'reference',
          title: 'reference',
          to: [{ type: 'article' }], // could be any document type
          inputComponent: ReferenceBrowser
        }
      ]
    },
    ]
}

reference-browser.js

import React, { useEffect, useState } from 'react';
import { RiExternalLinkLine } from 'react-icons/ri';
import { nanoid } from 'nanoid';
import {
  Card,
  Grid,
  Spinner,
  Stack,
  studioTheme,
  ThemeProvider,
  Text,
  Inline,
  Label,
  TextInput,
  Button
} from '@sanity/ui';
import FormField from 'part:@sanity/components/formfields/default';
import { PatchEvent, set } from 'part:@sanity/form-builder/patch-event';
import client from 'part:@sanity/base/client';

const List = ({ list, onClick }) => (
  <Grid
    autoRows='max'
    marginTop={2}
    padding={1}
    style={{ height: '300px', overflow: 'auto' }}
    columns={[2, 3, 4]}
    gap={[1, 1, 2, 3]}
  >
    {list.map(item => (
      <Card key={item._id} shadow={1} radius={2} padding={4}>
        <Stack space={[3]}>
          <Text marginBottom={[2]} weight='bold'>
            {item.title}
          </Text>
          <Inline space={[3, 3]}>
            <Button
              icon={RiExternalLinkLine}
              as='a'
              padding={[2]}
              href={`/desk/articles;${item._id}`} // edit 'articles' if your change document type
              text='Edit'
            />
            <Button
              padding={[2]}
              onClick={() => onClick(item)}
              text='Select'
              tone='primary'
            />
          </Inline>
        </Stack>
      </Card>
    ))}
  </Grid>
);

const ReferenceBrowser = React.forwardRef(({ onChange }) => {
  const [isFetching, setIsFetching] = useState(true);
  const [references, setReferences] = useState(null);

  // edit 'articles' in the query below if your change document type
  const search = (value = '') => {
    if (!references) setIsFetching(true);
    client
      .fetch(
        `*[
          _type == 'article'
          && title match '${value}*'
        ]
        {_id, _rev, title}`
      )
      .then(results => {
        setReferences(results);
        setIsFetching(false);
      });
  };

  useEffect(() => search(), []);

  const selectItem = ({ _id: _ref }) => {
    onChange(
      PatchEvent.from(set({ _key: nanoid(), _ref, _type: 'reference' }))
    );
  };

  if (isFetching) return <Spinner />;

  return (
    <FormField>
      <ThemeProvider theme={studioTheme}>
        <Inline space={[4]}>
          <Label>Search</Label>
          <TextInput
            fontSize={3}
            onChange={event => search(event.currentTarget.value)}
            padding={3}
            placeholder='search...'
          />
        </Inline>
        <List list={references} onClick={selectItem} />
      </ThemeProvider>
    </FormField>
  );
});

export default ReferenceBrowser;

Made for those who would like to have an alternative to browsing reference documents. Instead of the searchable select component, this component will provide a more visual interface, but still with the possibility to search. It looks almost like a small browser for your reference documents.

Could be useful for those who wish a more visual way to reference documents inside other documents.

Contributor