10up Block Components

repository·develop·Indexed 43 days ago

https://github.com/10up/block-components

A collection of React components and hooks designed for the WordPress block editor. Version 1.22.4 provides UI elements and data access patterns, including the registerBlockExtension API for adding custom settings to blocks, and components such as ContentPicker, ColorSetting, and ClipboardButton.

Tokens
51.8K
Snippets
157
Records
220
Agent score
55%

What's inside 10up Block Components

  1. How Post related components and hooks work

    develop

    The library provides a specialized set of components and hooks designed to interact with the WordPress block editor's data.

    Post related Components read or write information from the global post object or a PostContext. Examples include PostTitle, PostAuthor, and PostMeta.

    Post related Hooks provide programmatic access to the global post object or PostContext. Examples include usePost, useAllTerms, and usePostMetaValue.

    Use these when your custom block needs to be aware of the current post's state, such as its title, categories, or metadata.

  2. Use AbstractRepeater for custom data or Meta fields

    develop

    The AbstractRepeater is a base component designed for flexible data handling where you need to manage state externally, such as with WordPress Post Meta or custom stores. Unlike the standard Repeater, which is tied to block attributes, AbstractRepeater uses value and onChange props to control its data.

    This is the preferred method when implementing drag-and-drop reordering or when working with data stored in the REST API via core/data.

    import { AbstractRepeater } from './AbstractRepeater';
    import { useDispatch, useSelect } from '@wordpress/data';
    import { store as coreStore } from '@wordpress/core-data';
    
    export function Edit() {
        const { postId, metaValue } = useSelect((select) => ({
            postId: select('core/editor').getCurrentPostId(),
            metaValue: select(coreStore).getEditedEntityRecord('postType', 'post', postId)?.meta?.alternative_titles || []
        }));
    
        const { editEntityRecord } = useDispatch(coreStore);
        const updateMeta = (newValue) => {
            editEntityRecord('postType', 'post', postId, {
                meta: { alternative_titles: newValue }
            });
        };
    
        return (
            <AbstractRepeater
                onChange={updateMeta}
                value={metaValue}
                allowReordering={true}
            >
                {(item, index, setItem, removeItem) => (
                    <TextControl
                        value={item}
                        onChange={setItem}
                        placeholder={__('Add alternative title...', 'text-domain')}
                        onRemove={removeItem}
                    />
                )}
            </AbstractRepeater>
        );
    }
  3. Understand the `tenup/icons` data store structure

    develop

    The tenup/icons data store organizes icons into named sets. Each set contains a label and an array of icon objects. An icon object consists of a source, a name, and a label.

    {
        iconSets: {
            'example/theme': {
                label: 'Example',
                icons: [
                    {
                        source: "...",
                        name: "...",
                        label: "..."
                    }
                ]
            }
        }
    }
  4. Use PostContext to customize post data for child components

    develop

    The PostContext component allows you to provide a custom post object (ID and post type) to any nested components that are prefixed with Post (e.g., PostTitle). This is particularly useful when building custom blocks intended for use inside the WordPress Core Query Loop, where you want child components to reference the specific post being rendered in the loop rather than the main page post.

    To use this with the Core Query Loop, ensure your block's block.json includes the usesContext property with [ "postId", "postType" ]. You can then extract these values from the context prop and pass them into PostContext.

    import { PostContext, PostTitle } from '@10up/block-components';
    
    function BlockEdit(props) {
        const { context } = props;
        const { postId, postType, queryId } = context;
        // Determine if we are inside a query loop to manage editability
        const isDescendantOfQueryLoop = Number.isFinite(queryId);
    
        return (
            <PostContext postId={postId} postType={postType} isEditable={!isDescendantOfQueryLoop}>
                <PostTitle tagName="h2" className="wp-block-example-hero__title" />
            </PostContext>
        )
    }
  5. Use RichTextField for editor contexts outside of block edit

    develop

    The RichTextField component is a drop-in wrapper around WordPress's RichText designed for use in contexts outside of a block's standard edit function, such as within InspectorControls (the sidebar) or inside a Modal.

    It manages the isSelected state internally, so you do not need to provide it. It accepts all standard RichText props, allowing you to control the HTML value and formatting options.

    import { RichTextField } from '@10up/block-components';
    
    <RichTextField
        value={attributes.myNote}
        onChange={(value) => setAttributes({ myNote: value })}
    />
  6. Use the IconPicker components

    develop

    The @10up/block-components package provides several iterations of icon selection UI components. You can choose the component that best fits your UI needs:

    • InlineIconPicker: The recommended component for the best user experience. It allows for inline icon selection/preview.
    • IconPickerToolbarButton: A button designed for use within a toolbar (e.g., inside BlockControls).
    • IconPicker: A standard picker component, suitable for use within settings panels like InspectorControls.
    • Icon: A component used to display a previously selected icon.

    All picker components require a value object and an onChange handler. The value object should follow the shape { name: string, iconSet: string } (or similar depending on your registration), and the onChange callback provides the selected value.

    import {
        IconPicker,
        IconPickerToolbarButton,
        InlineIconPicker,
    } from '@10up/block-components';
    
    // Example usage in a block edit function
    const handleIconSelection = value => setAttributes({ icon: { name: value.name, iconSet: value.iconSet } });
    
    // Inside your render/return:
    <IconPickerToolbarButton value={icon} onChange={handleIconSelection} />
    <IconPicker value={icon} onChange={handleIconSelection} />
    <InlineIconPicker value={icon} onChange={handleIconSelection} />
  7. Use the ColorSetting component

    develop

    The ColorSetting component provides a color palette selection interface that includes an optional label and help text. It extends the functionality of the core ColorPalette component but is designed to be used within other Block Components or Blocks.

    Note: This component only handles the selection logic; it calls the onChange callback with the selected color value but does not automatically apply or update any CSS classes on your elements.

    import { ColorSetting } from '@10up/block-components';
    
    function MyComponent( props ) {
    
        return (
            <ColorSetting
                label={ __( 'Color Setting - Label', NAMESPACE ) }
                help={ __( 'Color Setting - Help Text', NAMESPACE ) }
                colors={ colors }
                value={ color }
                onChange={ ( color ) => setColor( color ) }
            />
        )
    }
  8. Customize ContentPicker fields and results

    develop

    You can intercept and modify the data flow of the ContentPicker using three specific filter props. It is highly recommended to wrap these functions in useCallback to prevent unnecessary re-renders.

    • queryFieldsFilter: Customize which fields are requested from the WordPress REST API. Note: if requesting custom fields, you must register them in PHP using register_rest_field.
    • searchResultFilter: Customize how search results are normalized after being fetched.
    • pickedItemFilter: Customize how items are displayed in the list of already picked items.
    import { ContentPicker } from '@10up/block-components';
    import { useCallback } from '@wordpress/element';
    
    function MyComponent( props ) {
        const queryFieldsFilter = useCallback( (fields, mode) => {
            if ( mode === 'post' ) {
                fields.push('excerpt');
            }
            return fields;
        }, [] );
    
        const searchResultFilter = useCallback( (item, result) => {
            const info = `<strong>ID:</strong> ${result.id}<br>${result.excerpt}`;
            return { ...item, url: '', info };
        }, [] );
    
        const pickedItemFilter = useCallback( (item, result) => {
            const info = `<strong>ID:</strong> ${result.id}<br>${result.excerpt.rendered}`;
            return {...item, url: '', info };
        }, [] );
    
        return (
            <ContentPicker
                onPickChange={ (pickedContent) => { console.log(pickedContent) } }
                mode="post"
                label={ "Please select a Post or Page:" }
                contentTypes={ [ 'post', 'page' ] }
                queryFieldsFilter={queryFieldsFilter}
                searchResultFilter={searchResultFilter}
                pickedItemFilter={pickedItemFilter}
            />
        )
    }
  9. Use the RichTextCharacterLimit component

    develop

    The RichTextCharacterLimit component allows you to apply character limits to rich text inputs within the WordPress block editor. It extends the standard RichText component, meaning it supports all props available to RichText (such as tagName, value, onChange, and allowedFormats).

    To use it, import it from @10up/block-components and provide the limit and enforce props to control how the character limit is applied.

    import { RichTextCharacterLimit } from '@10up/block-components';
    
    function BlockEdit(props) {
        const { attributes, setAttributes } = props;
        const { title } = attributes;
    
        return (
            <RichTextCharacterLimit
                limit={30}
                enforce={true}
                tagName="h2"
                value={title}
                placeholder={ __( 'Enter some text', NAMESPACE ) }
                onChange={(title) => setAttributes({title})}
                allowedFormats=[
                    'core/bold',
                    'core/link'
                ]}
            />
        )
    }