For the best experience, please view this on a larger device.

For the best experience, please view this on a larger device.

Combobox

Autocomplete input and command palette with a list of suggestions. Perfect for displaying large information.

Features

Code

Dark Mode

Children

Code

import { useState, useEffect } from "react"
import { addPropertyControls, ControlType } from "framer"
import ComboboxButton from "https://framer.com/m/Combobox-Button-ICar.js@ry4wgEJeU5VV2BTgliMR"
import ComboboxListItem from "https://framer.com/m/Combobox-List-Item-5RdT.js@DNgjyBNu7u4oPJ6cACVH"

/**
 * These annotations control how your component sizes
 * Learn more: https://www.framer.com/developers/#code-components-auto-sizing
 *
 * @framerSupportedLayoutWidth any
 * @framerSupportedLayoutHeight any
 */

function Dropdown(props) {
    const {
        dropdownStyles,
        searchWrapperStyles,
        inputStyles,
        listStyles,
        listItems,
        toggleSelf,
        activeitem,
        setSelected,
        searchIcon,
        searchPlaceholder,
        listItemComponent,
    } = props
    const [list, setList] = useState(listItems)

    const filterList = (e) => {
        if (e.target.value) {
            setList(
                list.filter((item) =>
                    item.toLowerCase().includes(e.target.value.toLowerCase())
                )
            )
        } else {
            setList(listItems)
        }
    }

    const selectItem = (item) => {
        setSelected(item)
        toggleSelf(false)
    }

    return (
        <div style={dropdownStyles}>
            <div style={searchWrapperStyles}>
                {searchIcon}
                <input
                    onChange={(e) => filterList(e)}
                    style={inputStyles}
                    name="qry"
                    placeholder={searchPlaceholder}
                />
            </div>
            <ul style={listStyles}>
                {list &&
                    list.map((item, index) => (
                        <ComboboxListItem
                            selected={item === activeitem ? 1 : 0}
                            key={index}
                            title={item}
                            style={{ width: "100%" }}
                            onClick={() => selectItem(item)}
                        />
                    ))}
            </ul>
        </div>
    )
}

export default function Combobox(props) {
    const {
        options,
        activeOption,
        placeHolder,
        dropdownStyles,
        iconComponent,
        searchStyles,
        uid,
        form,
    } = props
    const [show, setShow] = useState(false)
    const [activeitem, setSelected] = useState(activeOption)

    return (
        <div style={containerStyle}>
            <ComboboxButton
                onClick={() => setShow(!show)}
                placeholder={activeitem ? activeitem : placeHolder}
                style={{ width: "100%" }}
            />
            <input
                style={{ display: "none" }}
                name={uid}
                value={activeitem}
                form={form}
            />
            {show ? (
                <Dropdown
                    dropdownStyles={getWrapperStyles(dropdownStyles)}
                    searchWrapperStyles={getSearchWrapperStyles({
                        ...searchStyles.input,
                        border: dropdownStyles.border,
                    })}
                    listStyles={getListStyle(dropdownStyles)}
                    inputStyles={getInputStyles(searchStyles.input)}
                    searchIcon={iconComponent}
                    listItems={options}
                    toggleSelf={setShow}
                    setSelected={setSelected}
                    activeitem={activeitem}
                    searchPlaceholder={searchStyles.input.placeHolder}
                />
            ) : null}
        </div>
    )
}

const containerStyle = {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    overflow: "visible",
    position: "relative",
}

addPropertyControls(Combobox, {
    uid: {
        type: ControlType.String,
        title: "UID",
        description: "Unique identifier",
    },
    form: {
        type: ControlType.String,
        title: "Form",
        description: "The id of the form you wish to use this with",
    },
    options: {
        type: ControlType.Array,
        title: "Options",
        control: {
            type: ControlType.String,
        },
    },
    activeOption: {
        type: ControlType.String,
        title: "Active Option",
    },
    placeHolder: {
        type: ControlType.String,
        title: "Placeholder",
        defaultValue: "Select an option",
    },
    dropdownStyles: {
        type: ControlType.Object,
        title: "Combobox",
        controls: {
            border: {
                type: ControlType.Object,
                title: "Border",
                controls: {
                    color: {
                        type: ControlType.Color,
                        title: "Color",
                        defaultValue: "#27272A",
                    },
                    size: {
                        type: ControlType.Number,
                        title: "Size",
                        defaultValue: 1,
                    },
                    radius: {
                        type: ControlType.Number,
                        title: "Radius",
                        defaultValue: 6,
                    },
                },
            },
            fill: {
                type: ControlType.Color,
                defaultValue: "#050506",
            },
            maxHeight: {
                type: ControlType.Number,
                title: "Height",
                defaultValue: 350,
            },
            offset: {
                type: ControlType.Number,
                title: "Offset",
                defaultValue: 10,
            },
            padding: {
                type: ControlType.Number,
                defaultValue: 8,
            },
        },
    },
    iconComponent: {
        type: ControlType.ComponentInstance,
        title: "Search Icon Component",
    },
    searchStyles: {
        type: ControlType.Object,
        title: "Search Input",
        controls: {
            input: {
                title: "Input",
                type: ControlType.Object,
                controls: {
                    fontFamily: {
                        type: ControlType.String,
                        defaultValue: "Geist Regular",
                        title: "Font Family",
                    },
                    color: {
                        type: ControlType.Color,
                        defaultValue: "#ffffff",
                    },
                    fontSize: {
                        type: ControlType.Number,
                        defaultValue: 14,
                        title: "Font Size",
                    },
                    padding: {
                        type: ControlType.Number,
                        defaultValue: 8,
                    },
                    height: {
                        type: ControlType.Number,
                        title: "Height",
                        defaultValue: 40,
                    },
                    placeHolder: {
                        type: ControlType.String,
                        title: "Search Placeholder",
                        defaultValue: "Search...",
                    },
                },
            },
        },
    },
})

const getListStyle = (userStyles) => {
    const { padding } = userStyles
    return {
        display: "flex",
        flexDirection: "column",
        background: "transparent",
        border: "none",
        width: "100%",
        overflowY: "scroll",
        padding,
    }
}

const getInputStyles = (userStyles) => {
    const { color, fontFamily, fontSize } = userStyles
    return {
        height: "100%",
        background: "transparent",
        border: "none",
        width: "100%",
        outline: "none",
        color,
        fontSize,
        fontFamily,
    }
}

const getSearchWrapperStyles = (userStyles) => {
    const { padding, height, border } = userStyles
    return {
        display: "flex",
        flexDirection: "row",
        width: "100%",
        borderBottom: `${border.size}px solid`,
        borderColor: border.color,
        justifyContent: "start",
        alignItems: "center",
        gap: 8,
        minHeight: height,
        padding,
    }
}

const getWrapperStyles = (userStyles) => {
    const { border, fill, maxHeight, offset } = userStyles
    return {
        position: "absolute",
        width: "100%",
        display: "flex",
        flexDirection: "column",
        zIndex: "99",
        border: `${border.size}px solid`,
        borderColor: border.color,
        top: `calc(40px + ${offset}px)`,
        borderRadius: border.radius,
        maxHeight: `${maxHeight}px`,
        backgroundColor: fill,
    }
}

How to Use the Custom Combobox Component in Framer

In this guide, we'll explain how to use the custom Combobox component that we've built in Framer. This component allows you to create a dropdown with search functionality and customizable styles.

Please be aware that while this documentation includes code examples for utilizing and customizing the Combobox component, you can easily customize this component directly within Framer using the properties panel.

Step 1: Import the Component

First, you need to import the Combobox component into your project. Ensure that the component and its dependencies are correctly imported at the top of your file.

import Combobox from "https://framer.com/m/Combobox-cPyh.js@Zct0bzplwiz4iKA05mFu";

Step 2: Adding the Component to Your Canvas

You can now add the Combobox component to your canvas. Simply drag and drop it from the components panel in Framer.

Step 3: Configuring the Properties

The Combobox component comes with several property controls that allow you to customize its behavior and appearance. Here is a list of the properties you can configure:

UID

  • Description: The unique identifier for the combobox input field.

  • Control Type: String

  • Required: Yes

  • Example:

    <Combobox uid="unique-combobox-id" />

Form

  • Description: The id of the form you wish to use this combobox with.

  • Control Type: String

  • Example:

    <Combobox form="myForm" />

Options

  • Description: An array of strings representing the options available in the dropdown.

  • Control Type: Array of Strings

  • Example:

    <Combobox options={["Option 1", "Option 2", "Option 3"]} />

Active Option

  • Description: The currently selected option.

  • Control Type: String

  • Example:

    <Combobox activeOption="Option 1" />

Placeholder

  • Description: The placeholder text displayed in the combobox input when no option is selected.

  • Control Type: String

  • Default Value: "Select an option"

  • Example:

    <Combobox placeHolder="Choose an option" />

Dropdown Styles

  • Description: Object containing styles for the dropdown menu.

  • Control Type: Object

  • Example:

    <Combobox
      dropdownStyles={{
        border: {
          color: "#27272A",
          size: 1,
          radius: 6,
        },
        fill: "#050506",
        maxHeight: 350,
        offset: 10,
        padding: 8,
      }}
    />

Icon Component

  • Description: A Framer component instance used as a search icon inside the dropdown's search bar.

  • Control Type: Component Instance

  • Example:

    <Combobox iconComponent={<YourIconComponent />} /> q

Search Styles

  • Description: Object containing styles for the search input inside the dropdown.

  • Control Type: Object

  • Example:

    <Combobox
      searchStyles={{
        input: {
          fontFamily: "Geist Regular",
          color: "#ffffff",
          fontSize: 14,
          padding: 8,
          height: 40,
          placeHolder: "Search...",
        },
      }}
    />


Example Usage

Let's go through a practical example to see how all the properties come together:

import React from "react";
import Combobox from "./path-to-your-Combobox-component";
import SearchIcon from "./path-to-your-SearchIcon-component";

export default function MyComponent() {

  return (
    <Combobox
      uid="unique-combobox-id"
      form="myForm"
      options={["Option 1", "Option 2", "Option 3"]}
      activeOption="Option 1"
      placeHolder="Choose an option"
      dropdownStyles={{
        border: {
          color: "#27272A",
          size: 1,
          radius: 6,
        },
        fill: "#050506",
        maxHeight: 350,
        offset: 10,
        padding: 8,
      }}
      iconComponent={<SearchIcon />}
      searchStyles={{
        input: {
          fontFamily: "Geist Regular",
          color: "#ffffff",
          fontSize: 14,
          padding: 8,
          height: 40,
          placeHolder: "Search...",
        },
      }}
    />
  );
}

In this example, we have configured the Combobox with a unique identifier, hooks it to a form, defines some options, and customizes the dropdown and search input styles.

blak/ui