Cannot Focus Input Field When NextUI Drawer Sidebar is Open

I have a React application where I’m using the @nextui-org/react library to implement a sidebar using the Drawer component. Within my main content area, I have an input field. The issue is that when the sidebar is open, clicking on the input field doesn’t focus it. Instead of the input gaining focus, one of the items within the open sidebar’s navigation list becomes focused.

This prevents users from interacting with the input while the sidebar is visible. Removing the DrawerContent component from the Sidebar implementation resolves the issue, suggesting the problem lies within that component or its interaction with the Drawer. The presence of <span data-focus-scope-start="true" hidden="" aria-hidden="true"></span> within the Drawer when open makes me suspect it’s related to focus management.

I initially suspected the portalContainer prop was causing an issue with event handling, so I removed it, but the problem persisted. I also checked the z-index of the relevant elements using the browser’s developer tools to rule out any stacking order issues.

Through testing, I isolated the problem to the DrawerContent component. When the sidebar is open and I click the input, I expect the input field to receive focus, allowing the user to type. However, the actual result is that the input does not get focused, and instead, an item in the sidebar’s navigation receives the focus. I also noticed the <span data-focus-scope-start="true" ...> element and suspect it is involved in incorrectly managing focus.

LayoutPanel.js:

import React from "react";
import { Outlet, useLocation, useNavigate } from "react-router";
import Sidebar from "../components/Sidebar";
import {
  Button,
  Card,
  CardBody,
  CardHeader,
  Divider,
  useDisclosure,
} from "@nextui-org/react";
import { Icon } from "@iconify/react";
import { images } from "../utils/images";

const LayoutPanel = () => {
  const { isOpen, onOpen, onOpenChange } = useDisclosure();

  const navigate = useNavigate();
  const location = useLocation();

  return (
    <div>
      {/* <HeaderNavigation /> */}
      <div className="flex w-full">
        <Sidebar isOpen={isOpen} onOpenChange={onOpenChange} />
        <Card className="flex-1 m-3 min-h-[calc(100vh-24px)]">
          <CardHeader className="h-[76px]">
            <div className="flex items-center gap-2">
              {!isOpen && (
                <Button isIconOnly variant="light" onPress={onOpenChange}>
                  <Icon icon="solar:siderbar-outline" width={24} />
                </Button>
              )}
              <img
                src={images.logo}
                alt="logo"
                className="object-contain h-6 dark:invert"
              />
            </div>
          </CardHeader>
          <Divider />
          <CardBody className="container mx-auto max-w-7xl text-start">
            <Outlet />
          </CardBody>
        </Card>
      </div>
      {/* <Footer /> */}
    </div>
  );
};

export default LayoutPanel;

Sidebar.js:

import React from "react";
import {
  Drawer,
  DrawerContent,
  DrawerHeader,
  DrawerBody,
  Listbox,
  ListboxItem,
  Accordion,
  Button,
  AccordionItem,
  cn,
  Divider,
} from "@nextui-org/react";
import sidebarNavigation from "../utils/sidebarNavigation";
import { Icon } from "@iconify/react";

const Sidebar = ({ isOpen, onOpenChange }) => {
  return (
    <div
      id="sidebar"
      className={cn(
        "transition-all absolute md:relative duration-300 ease-in-out overflow-hidden",
        isOpen ? "w-[336px]" : "w-0"
      )}
    >
      <Drawer
        isDismissable={false}
        hideCloseButton
        isKeyboardDismissDisabled={false}
        portalContainer={document.getElementById("sidebar") || undefined}
        backdrop={window.innerWidth < 768 && isOpen ? "blur" : "transparent"}
        classNames={{
          wrapper: "!items-stretch w-auto relative",
          base: "data-[placement=right]:sm:my-3 data-[placement=left]:sm:my-3 rounded-e-large rounded-s-none",
          body: "pe-0",
          header: "p-[calc(1rem+2px)] ",
        }}
        shouldBlockScroll
        isOpen={isOpen}
        onOpenChange={onOpenChange}
      >
        <DrawerContent>
          <DrawerHeader className="flex justify-between gap-3 ">
            <h3>منو</h3>
            <Button isIconOnly variant="light" onPress={onOpenChange}>
              <Icon icon="solar:siderbar-outline" width={24} />
            </Button>
          </DrawerHeader>
          <Divider />
          <DrawerBody>
            <Listbox
              variant="flat"
              className="overflow-y-auto pe-3 ps-0"
            >
              {sidebarNavigation.map((menuItem) =>
                menuItem.subItems ? (
                  <ListboxItem key={menuItem.title}>
                    <Accordion showDivider={false} className="space-y-3">
                      <AccordionItem
                        key={menuItem.title}
                        aria-label={menuItem.title}
                        startContent={
                          <div
                            className={`flex items-center rounded-small justify-center ${menuItem.color} w-9 h-9`}
                          >
                            <img
                              src={menuItem.icon}
                              className="object-contain invert"
                              width={24}
                              alt={menuItem.title}
                            />
                          </div>
                        }
                        subtitle={menuItem.subtitle}
                        classNames={{
                          trigger: "p-0",
                          content: "py-0 ps-3",
                        }}
                        title={menuItem.title}
                      >
                        <Listbox
                          variant="flat"
                          aria-label={`زیرمنو ${menuItem.title}`}
                          classNames={{
                            list: cn("border-s border-default-200 ps-4"),
                          }}
                        >
                          {menuItem.subItems.map((subItem) => (
                            <ListboxItem
                              key={subItem.title}
                              textValue={subItem.title}
                              href={subItem.path}
                              startContent={
                                <div
                                  className={`flex items-center rounded-small justify-center ${menuItem.color} w-7 h-7`}
                                >
                                  <img
                                    src={subItem.icon}
                                    width={20}
                                    className="object-contain"
                                    alt={subItem.title}
                                  />
                                </div>
                              }
                            >
                              <span>{subItem.title}</span>
                            </ListboxItem>
                          ))}
                        </Listbox>
                      </AccordionItem>
                    </Accordion>
                  </ListboxItem>
                ) : (
                  <ListboxItem
                    title={menuItem.title}
                    description={menuItem.subtitle}
                    classNames={{
                      base: "gap-3",
                    }}
                    startContent={
                      <div className="ms-2">
                        <div
                          className={`flex items-center rounded-small justify-center ${menuItem.color} w-9 h-9`}
                        >
                          <img
                            src={menuItem.icon}
                            width={20}
                            className="invert"
                            alt={menuItem.title}
                          />
                        </div>
                      </div>
                    }
                  >
                    {menuItem.title}
                  </ListboxItem>
                )
              )}
            </Listbox>
          </DrawerBody>
        </DrawerContent>
      </Drawer>
    </div>
  );
};

export default Sidebar;

FormFastGroup.js:

import { Controller, useForm } from "react-hook-form";
import { Button, Form, Input } from "@nextui-org/react";

const FormFastGroup = () => {
  const { handleSubmit, control } = useForm();

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <Form
      className="w-full max-w-xs flex flex-col gap-4"
      onSubmit={handleSubmit(onSubmit)}
    >
      <Controller
        control={control}
        name="name"
        render={({
          field: { name, value, onChange, onBlur, ref },
          fieldState: { invalid, error },
        }) => (
          <Input
            ref={ref}
            isRequired
            errorMessage={error?.message}
            // Let React Hook Form handle validation instead of the browser.
            validationBehavior="aria"
            isInvalid={invalid}
            label="Name"
            name={name}
            value={value}
            onBlur={onBlur}
            onChange={onChange}
          />
        )}
        rules={{ required: "Name is required." }}
      />
      <Button type="submit">Submit</Button>
    </Form>
  );
};

export default FormFastGroup;

FastGroup.js:

import React from "react";
import FormFastGroup from "../components/FormFastGroup";

const FastGroup = () => {
  return (
    <div className="flex flex-col gap-4">
      <h3 className="font-bold text-xl">ارسال سریع و گروهی</h3>
      <div>
        <FormFastGroup />
      </div>
    </div>
  );
};

export default FastGroup;