Here's a quick summary of everything we released in Q1 2024.

Hygraph
Docs

Table renderer

You can define how custom field values are displayed in the content table.

To enable custom table-cell rendering in your app, add FieldExtensionFeature.TableRenderer to the features array in the extension declaration.

import {
FieldExtensionType,
FieldExtensionFeature,
} from '@graphcms/uix-react-sdk';
const declaration = {
extensionType: 'field',
fieldType: FieldExtensionType.JSON,
name: 'Custom JSON',
features: [
FieldExtensionFeature.FieldRenderer,
FieldExtensionFeature.TableRenderer,
],
};

The SDK provides a isTableCell boolean that you can use to detect that the current extension instance is rendered in the content table:

How you handle table-cell rendering is up to you. Hygraph will only enforce a cell height of 60px in order to preserve other fields' functionality in the table layout.

Let's emulate a simple string field preview that conditionally displays the value in a paragraph:

#Multiple values

What happens if your extension supports lists? By combining the two features, FieldExtensionFeature.TableRenderer and FieldExtensionFeature.ListRenderer, you can determine how multiple-value fields should behave in content table.

Let us augment the previous example to account for list values:

import {
Wrapper,
useFieldExtension,
FieldExtensionType,
FieldExtensionFeature,
} from '@graphcms/uix-react-sdk';
const declaration = {
extensionType: 'field',
fieldType: FieldExtensionType.STRING,
name: 'Custom string',
features: [
FieldExtensionFeature.FieldRenderer,
FieldExtensionFeature.TableRenderer,
FieldExtensionFeature.ListRenderer,
],
};
const CustomStringInput = () => {
const {
value,
onChange,
isTableCell,
field: { isList },
} = useFieldExtension();
if (isTableCell) {
if (isList) {
return (
<div>
{value.map((item) => (
<p>{item}</p>
))}
</div>
);
}
return <p>{value}</p>;
}
if (isList) {
return (
<input
value={value}
onChange={({ target: { value: val } }) => onChange([...value, val])}
/>
);
}
return (
<input
value={value}
onChange={({ target: { value: val } }) => onChange(val)}
/>
);
};
const Extension = () => {
return (
<Wrapper declaration={declaration}>
<CustomStringInput />
</Wrapper>
);
};

#Preview expansion

The example above would work for simple cases, but you'll likely need more space than a table cell allows.

For those cases, the SDK provides you with tools to display the content of a custom field in full-screen mode.

Extract the expand handler that takes a boolean as an argument and isExpanded prop by calling the useFieldExtension hook:

const { isTableCell, expand, isExpanded } = useFieldExtension();

Instead of displaying the value directly in the table cell, you can now render a button that would expand the preview. A basic example would be something like this:

if (isTableCell) {
if (isExpanded) {
return (
<div>
<p>{value}</p>
<button onClick={() => expand(false)}>Close</button>
<div>
);
} else {
return (
<button onClick={() => expand(true)}>
Preview
</button>
);
}
}