WordPress 6.9 and the Site Editor work are not only a theme developer’s concern. The admin interface itself is being restructured. If you have built settings pages the old way, stacking PanelBody inside PanelBody with a PanelRow for every control, you know how that ages. Adding one field means going back into a pile of imperative JSX.
Core now offers a declarative option. Here is how to use the DataForm component for DataForm plugin settings pages. It is the same tech behind the new Site Editor experience, and after a configuration-driven UI, hand-wrapping TextareaControl tags loses its appeal fast.
Why DataForm matters for admin UI
Traditional WordPress React development asks for a lot of boilerplate before a simple form renders. Import every control, track each one’s state, lay it all out by hand. It breaks easily. For more on what else changed, I wrote about why WordPress 6.9 is a major win for developers.
With DataForm you define your fields as a JSON-like configuration object. The component renders them, mapping each one to the right UI control based on its data type. It also handles layout types such as cards and panels without extra work on your side.
Step 1: installing dependencies
You need the @wordpress/dataviews package. If you already build with wp-scripts, it drops straight in. Run this in your plugin directory:
npm install @wordpress/dataviews --save
One gotcha on the import. Import from @wordpress/dataviews/wp so that WordPress resolves the dependencies correctly, as the official package documentation notes.
import { DataForm } from '@wordpress/dataviews/wp';
Step 2: defining your fields configuration
Rather than rendering components, you define a fields array where each object is one setting. For DataForm plugin settings pages you set the id, label and type. Want a particular UI control, like a toggle or a textarea? Set the Edit property.
const fields = [
{
id: 'message',
label: __( 'Announcement Message', 'my-plugin' ),
type: 'text',
Edit: 'textarea',
},
{
id: 'display',
label: __( 'Display Bar', 'my-plugin' ),
type: 'boolean',
Edit: 'toggle',
},
{
id: 'size',
label: __( 'Font Size', 'my-plugin' ),
type: 'text',
Edit: 'toggleGroup',
elements: [
{ value: 'small', label: __( 'Small', 'my-plugin' ) },
{ value: 'medium', label: __( 'Medium', 'my-plugin' ) },
{ value: 'large', label: __( 'Large', 'my-plugin' ) },
],
},
];
Step 3: layout and grouping
Grouping is where DataForm earns its keep. Wrap fields into sections and pick a regular, panel, card or row layout. The card layout is the one that gets closest to the modern Gutenberg sidebar look.
const form = {
fields: [
{
id: 'general-settings',
label: __( 'General', 'my-plugin' ),
children: [ 'message', 'display' ],
layout: { type: 'card', withHeader: false },
},
{
id: 'appearance-settings',
label: __( 'Appearance', 'my-plugin' ),
children: [ 'size' ],
layout: { type: 'card', isOpened: false },
},
],
};
Step 4: connecting to state
Three settings used to mean three useState hooks. With DataForm everything lives in one object, which matches how WordPress stores settings in the REST API when you register the setting with the object type.
const SettingsPage = () => {
const { settings, setSettings, saveSettings } = bbioon_useSettings();
return (
<DataForm
data={ settings }
fields={ fields }
form={ form }
onChange={ ( edits ) =>
setSettings( ( current ) => ( {
...current,
...edits,
} ) )
}
/>
);
};
The onChange callback hands you only the edits, meaning the fields that changed. That is why the spread operator merges the updates into current state instead of replacing it, and why an update does not wipe your other settings.
The takeaway
Moving to DataForm plugin settings pages buys you more than a modern look. You get an architecture that follows where WordPress Core is going, and you spend your time on the data logic of your plugin instead of fighting CSS.
If DataForm is eating your dev hours, I can take that off your plate. I have been wrestling with WordPress since the 4.x days.
For deeper documentation on validation or asynchronous elements, read the WordPress 6.9 DataViews announcement. Then go ship something clean.