Elements positioning in a custom block

You would need a combination of JavaScript for the custom block, and CSS to make the H1 span across both columns.

The JavaScript would be like this:

registerBlockType('my-plugin/two-columns', {
    title: 'Two Columns',
    icon: 'screenoptions',
    category: 'common',
    attributes: {
        title: {
            type: 'string',
        },
        imageUrl: {
            type: 'string',
        },
    },
    edit({ attributes, setAttributes }) {
        const handleTitleChange = (title) => {
            setAttributes({ title });
        };

        const handleImageChange = (imageUrl) => {
            setAttributes({ imageUrl });
        };

        return (
            <div className="two-columns-block">
                <div className="two-columns-block-column two-columns-block-column-left">
                    <h1 className="two-columns-block-title">
                        <PlainText
                            value={attributes.title}
                            onChange={handleTitleChange}
                        />
                    </h1>
                </div>
                <div className="two-columns-block-column two-columns-block-column-right">
                    <MediaUpload
                        onSelect={handleImageChange}
                        type="image"
                        value={attributes.imageUrl}
                        render={({ open }) => (
                            <Button className="button button-large" onClick={open}>
                                {!attributes.imageUrl ? 'Select Image' : 'Change Image'}
                            </Button>
                        )}
                    />
                    {attributes.imageUrl && (
                        <img src={attributes.imageUrl} alt="Image" />
                    )}
                </div>
            </div>
        );
    },
    save({ attributes }) {
        return (
            <div className="two-columns-block">
                <div className="two-columns-block-column two-columns-block-column-left">
                    <h1 className="two-columns-block-title">{attributes.title}</h1>
                </div>
                <div className="two-columns-block-column two-columns-block-column-right">
                    {attributes.imageUrl && (
                        <img src={attributes.imageUrl} alt="Image" />
                    )}
                </div>
            </div>
        );
    },
});

This code defines a custom block called “Two Columns” that contains an h1 tag in the left column and an image in the right column. The edit function is used to render the block in the block editor, and the save function is used to render the block in the frontend.

To make the h1 tag look like it spans both columns, you can use the following CSS:

.two-columns-block {
    display: flex;
}

.two-columns-block-column {
    width: 50%;
}

.two-columns-block-title {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
}

This CSS uses the display: flex property to make the container element a flex container. It sets the width of each column to 50%, which makes each column take up half the width of the container.

The position: absolute property is used to position the h1 tag in the middle of the left column. The top: 50% and left: 50% properties are used to position the h1 tag in the center of the column. The transform: translate(-50%, -50%) property is used to move the h1 tag up and to the left by half its width and height, which centers it in the column.

The z-index: 1 property is used to make the h1 tag appear on top of the image in the right column. This makes it look like the h1 tag spans both columns.