Dropdown Button Overlay

I was trying to bundle a number of actions that could be taken on a field based on its contents using a dropdown field to select the action, then another smaller button to execute it. However, the dropdown field seems to be stuck in the iframe and clicking on the dropdown causes some pretty ugly UX.

From my testing, it seems like the dropdown button is pretty much useless in a field extension. Am I missing something for how the dropdown should be configured for this use case?

Hi @nroth, could you please provide a few screenshots and a code snippet showing what you mean?

Yeah, i’ll see if I can put together a generic example. But, a simple extreme case would be a basic field extension plugin with a dropdown field just below the field it is associated with, but with 50 items in the dropdown.

When I use a dropdown in a field extension, it seems like the dropdown is stuck within the iframe, so it doesn’t behave like the native dropdowns anywhere else on the form.

This is just a simple field extension with a dropdown. I built a component that if you pass it a number of options you want, it dynamically generates them for you. Here it is as the only child to the Canvas element as-is. Because it is in an iframe, it can’t overlay the fields just below. It expands a minimum amount, which causes the iframe to expand a little bit.

Demo

Here is a video of it in action

Question

My core question here is, is the behavior shown in the video/screenshot above expected? I assume there isn’t a way for it to work outside the iframe, so to me it seems like it would be useless in a field extension. I supposed I could add some styling on the dropdown to force its minimum height, but still the UX for that would be kind of janky.

Code

This component might not make complete sense as-is, but it is just a quick adaption of what I was going for. The idea being I could have one or more actions registered to a field. If there is more than 1, then it uses the dropdown component (the original idea was to add a button next to the dropdown to execute the selected option, but excluded that here to avoid additional styling).

I just made it so it outputs a bunch of options in the dropdown menu. This dropdown is placed as a child of a Canvas component, where I followed this example to import the styles as suggested.

import React, { useState } from 'react';
import {
  Button,
  Dropdown,
  DropdownOption,
  DropdownMenu,
  CaretUpIcon,
  CaretDownIcon,
} from 'datocms-react-ui';

// Define a type for the option structure expected in the dropdown
interface IDropdownOption {
  id: string;
  text: string;
}

// Props type definition for the component
interface IDropdownProps {
  numberOfOptions: number; // The N number of options to display
}

const SimpleDropdown: React.FC<IDropdownProps> = ({ numberOfOptions }) => {
  // Generate an array of options based on the numberOfOptions prop
  const options: IDropdownOption[] = Array.from({ length: numberOfOptions }, (_, index) => ({
    id: `option-${index + 1}`,
    text: `Option ${index + 1}`,
  }));

  const [selectedOption, setSelectedOption] = useState<IDropdownOption>(options[0]);

  const handleChange = (option: IDropdownOption) => {
    setSelectedOption(option);
  };

  return (
    <div>
      {options.length > 1 && (
        <Dropdown
          renderTrigger={({ open, onClick }) => (
            <Button
              onClick={onClick}
              rightIcon={open ? <CaretUpIcon /> : <CaretDownIcon />}
            >
              {selectedOption.text} {/* Reflecting the selected option text */}
            </Button>
          )}
        >
          <DropdownMenu>
            {options.map((option) => (
              <DropdownOption
                key={option.id}
                onClick={() => handleChange(option)}
              >
                {option.text}
              </DropdownOption>
            ))}
          </DropdownMenu>
        </Dropdown>
      )}
    </div>
  );
};

export default SimpleDropdown;

Bump.

@nroth,

My apologies again for the delay on this. We’ll work on better tracking for forum posts across categories.

This seems like a bug/oversight to me, because the autoresizer isn’t properly accounting for the dynamic height of the dropdown. And it should probably be an overlay instead of an inline iframe, I’m guessing. Unfortunately, this behavior seems to be hardcoded into our datocms-react-ui plugin design system and will require some changes on our side. I’ll report it to the devs right away.

In the meantime, here is a workaround that might be better than nothing…

Demo video

Implementation

First I modified the <Dropdown/> element to manually resize the iframe:

<Dropdown
    renderTrigger={({open, onClick}) => (
        <Button
            onClick={() => {
                ctx.stopAutoResizer() // If we don't stop it, the autosizer will keep fighting us
                ctx.setHeight(300).then(() => onClick()) // The height determines how many options are shown at once
            }}
            rightIcon={open ? <CaretUpIcon/> : <CaretDownIcon/>}
        >
            {selectedOption.text} {/* Reflecting the selected option text */}
        </Button>
    )}
>

Then I also changed the handleChange handler to resume autoresize after a selection has been made:

const handleChange = (option: IDropdownOption) => {
    setSelectedOption(option);
    ctx.startAutoResizer(); // Shrink it back down on selection
};

You can see the whole file here:

I know it’s kinda hacky, but I think a cleaner fix would require upstream changes from us :frowning: I’ll let the devs know and report back as soon as I can.

I wanted to check on the status of this if this is a potential long-term feature request or something that could be fixed quickly.

This issue also exists for the SelectField when building a field editor extension. This is what my implementation of the button dropdown and selectfield dropdown looks like when using the form, which just looks not great. I tried using both approaches to see if one works better than the other, but both cause significant layout shift.

Sorry, no direct update yet. It’s still in progress, and I’ve pinged the dev assigned to it as a reminder.

Should be fixed in v1.0.2 (both datocms-plugin-sdk and datocms-react-ui):