Search 10.16.0

ARIA
RTL

Search enables users to specify a word or a phrase to find relevant pieces of content without the use of navigation.

Default

"use client";

import { useMemo, useState } from "react";
import {
  MenuItem,
  Search,
  searchFilterItems,
  searchGetItemIndex,
} from "@heathmont/moon-core-tw";

interface Item {
  children?: React.ReactNode;
  href?: string;
  id: string;
}

interface Items {
  items: Item[];
  heading?: string;
  id: string;
}

const Default = () => {
  const [open, setOpen] = useState<boolean>(false);
  const [search, setSearch] = useState("");

  const filteredItems = useMemo(
    () =>
      searchFilterItems(
        [
          {
            heading: "Results",
            id: "results",
            items: [
              {
                id: "home",
                children: "Home",
                href: "#home",
              },
              {
                id: "settings",
                children: "Settings",
                href: "#settings",
              },
              {
                id: "projects",
                children: "Projects",
                closeOnSelect: false,
                onClick: () => {
                  alert("projects");
                },
              },
            ],
          },
          {
            heading: "Other",
            id: "other",
            items: [
              {
                id: "developer-settings",
                children: "Developer settings",
                href: "#developer-settings",
              },
              {
                id: "privacy-policy",
                children: "Privacy policy",
                href: "#privacy-policy",
              },
              {
                id: "log-out",
                children: "Log out",
                onClick: () => {
                  alert("Logging out...");
                },
              },
            ],
          },
        ],
        search,
      ),
    [search],
  );

  return (
    <div className="w-full xl:mx-32">
      <Search
        onChangeSearch={setSearch}
        onChangeOpen={setOpen}
        search={search}
        isOpen={open}
      >
        <Search.Input>
          <Search.Input.Icon />
          <Search.Input.Input />
          <Search.Input.ButtonClear>Clear</Search.Input.ButtonClear>
        </Search.Input>

        <Search.Result>
          {filteredItems.length ? (
            filteredItems.map((list: Items) => (
              <ul className="space-y-1" key={list.id}>
                <li>
                  <Search.ResultHeading>{list.heading}</Search.ResultHeading>
                  {list.items.map(({ id, children, href, ...rest }: Item) => (
                    <Search.ResultItem
                      key={id}
                      index={searchGetItemIndex(filteredItems, id)}
                      closeOnSelect={true}
                      {...rest}
                    >
                      {href ? (
                        <a href={href}>
                          <MenuItem>
                            <MenuItem.Title>{children}</MenuItem.Title>
                            <span className="text-moon-12 text-trunks">
                              {href}
                            </span>
                          </MenuItem>
                        </a>
                      ) : (
                        <MenuItem>
                          <MenuItem.Title>{children}</MenuItem.Title>
                          <span className="text-moon-12 text-trunks">
                            Action
                          </span>
                        </MenuItem>
                      )}
                    </Search.ResultItem>
                  ))}
                </li>
              </ul>
            ))
          ) : (
            <Search.NoResults />
          )}
        </Search.Result>
      </Search>
    </div>
  );
};

export default Default;

    With transition

    To add an additional transition effect when Search results appear smoothly, you can wrap a <Search.Result /> sub-component with a <Search.Transition />.

    "use client";
    
    import { useMemo, useState } from "react";
    import {
      MenuItem,
      Search,
      searchFilterItems,
      searchGetItemIndex,
    } from "@heathmont/moon-core-tw";
    
    interface Item {
      children?: React.ReactNode;
      href?: string;
      id: string;
    }
    
    interface Items {
      items: Item[];
      heading?: string;
      id: string;
    }
    
    const WithTransition = () => {
      const [open, setOpen] = useState<boolean>(false);
      const [search, setSearch] = useState("");
    
      const filteredItems = useMemo(
        () =>
          searchFilterItems(
            [
              {
                heading: "Results",
                id: "results",
                items: [
                  {
                    id: "home",
                    children: "Home",
                    href: "#home",
                  },
                  {
                    id: "settings",
                    children: "Settings",
                    href: "#settings",
                  },
                  {
                    id: "projects",
                    children: "Projects",
                    closeOnSelect: false,
                    onClick: () => {
                      alert("projects");
                    },
                  },
                ],
              },
              {
                heading: "Other",
                id: "other",
                items: [
                  {
                    id: "developer-settings",
                    children: "Developer settings",
                    href: "#developer-settings",
                  },
                  {
                    id: "privacy-policy",
                    children: "Privacy policy",
                    href: "#privacy-policy",
                  },
                  {
                    id: "log-out",
                    children: "Log out",
                    onClick: () => {
                      alert("Logging out...");
                    },
                  },
                ],
              },
            ],
            search,
          ),
        [search],
      );
    
      return (
        <div className="w-full xl:mx-32">
          <Search
            onChangeSearch={setSearch}
            onChangeOpen={setOpen}
            search={search}
            isOpen={open}
          >
            <Search.Input>
              <Search.Input.Icon />
              <Search.Input.Input />
              <Search.Input.ButtonClear>Clear</Search.Input.ButtonClear>
            </Search.Input>
    
            <Search.Transition>
              <Search.Result>
                {filteredItems.length ? (
                  filteredItems.map((list: Items) => (
                    <ul className="space-y-1" key={list.id}>
                      <li>
                        <Search.ResultHeading>{list.heading}</Search.ResultHeading>
                        {list.items.map(({ id, children, href, ...rest }: Item) => (
                          <Search.ResultItem
                            key={id}
                            index={searchGetItemIndex(filteredItems, id)}
                            closeOnSelect={true}
                            {...rest}
                          >
                            {href ? (
                              <a href={href}>
                                <MenuItem>
                                  <MenuItem.Title>{children}</MenuItem.Title>
                                  <span className="text-moon-12 text-trunks">
                                    {href}
                                  </span>
                                </MenuItem>
                              </a>
                            ) : (
                              <MenuItem>
                                <MenuItem.Title>{children}</MenuItem.Title>
                                <span className="text-moon-12 text-trunks">
                                  Action
                                </span>
                              </MenuItem>
                            )}
                          </Search.ResultItem>
                        ))}
                      </li>
                    </ul>
                  ))
                ) : (
                  <Search.NoResults />
                )}
              </Search.Result>
            </Search.Transition>
          </Search>
        </div>
      );
    };
    
    export default WithTransition;
    

      These are props specific to the Search component:

      Name
      Type
      Default
      className
      string-
      isOpen*
      boolean-
      onChangeOpen*
      (isOpen: boolean) => void-
      onChangeSearch*
      (search: string) => void-
      onChangeSelected
      (value: number) => void-
      search*
      string-

      Properties indicated with * are required.

      Search.Input

      These are props specific to the Search.Input component:

      Name
      Type
      Default
      className
      string-

      Search.Input.Icon

      These are props specific to the Search.Input.Icon component:

      Name
      Type
      Default
      className
      string-

      Search.Input.Input

      These are props specific to the Search.Input.Input component:

      Name
      Type
      Default
      autoFocus
      booleanfalse
      className
      string-
      placeholder
      stringSearch

      Search.Input.ButtonClear

      These are props specific to the Search.Input.ButtonClear component:

      Name
      Type
      Default
      className
      string-

      Search.Transition

      These are props specific to the Search.Transition component:

      Name
      Type
      Default
      className
      string-

      Search.NoResults

      These are props specific to the Search.NoResults component:

      Name
      Type
      Default
      className
      string-

      Search.Result

      These are props specific to the Search.Result component:

      Name
      Type
      Default
      className
      string-

      Search.ResultItem

      These are props specific to the Search.ResultItem component:

      Name
      Type
      Default
      className
      string-

      Search.ResultHeading

      These are props specific to the Search.ResultHeading component:

      Name
      Type
      Default
      className
      string-