Skip to content

mejdi14/KMP-Searchable-Dropdown

Repository files navigation

Welcome to KMP Searchable Dropdown 👋

Minimum API Level Maven Central License: MIT Android Arsenal

✨ Demo

Installation

Add this to your module's build.gradle file (make sure the version matches the JitPack badge above):

dependencies {
	...
	implementation("io.github.mejdi14:KMP-Searchable-Dropdown:1.1.0")
}

🔥How to use

/* use your own list of objects
here I used this Data Class as an example:
data class People(
    val name: String,
    val photo: DrawableResource,
    val job: String
)
*/
val people = listOf(
    People("Arij", Res.drawable.student2, "Software engineer"),
    People("Mejdi", Res.drawable.student1, "Software engineer"),
    People("Sami", Res.drawable.student3, "Designer"),
    )
    SearchableDropdown(
        items = people,
        searchSettings = SearchSettings(
            searchProperties = listOf(
                People::name,
                People::job,
            )
        ),
        dropdownConfig = DropdownConfig(shape = RoundedCornerShape(8.dp)),
        itemContentConfig = ItemContentConfig.Default(DefaultDropdownItem<Student>(title = Student::name)),
        ),
    )

Search Settings

Properties Table

Fields Table for SearchSettings

Field Type Default Value Description
searchEnabled Boolean true Indicates whether the search functionality is enabled (also controles its visibility).
searchProperties List<KProperty1<T, *>> emptyList() A list of properties in your object to be searched.
separator @Composable () -> Unit { SearchSeparator() } A separator between the search and the items of the Dropdown.
searchIcon SearchIcon SearchIcon() Configuration for the search icon, including its appearance and behavior.
searchInput SearchInput SearchInput() Configuration for the search input, such as placeholders or initial text.
searchType SearchType SearchType.CONTAINS Defines the search type (e.g., CONTAINS, STARTS_WITH, etc.).
ignoreCase Boolean true Determines whether the search is case-insensitive.
searchActionListener SearchActionListener<T> object : SearchActionListener<T> { ... } Listener for handling search-related actions, such as text changes or results.

Dropdown Config

Fields Table for DropdownConfig

Field Type Default Description
backgroundColor Color Color.White The background color of the dropdown.
shape Shape RoundedCornerShape(20.dp) The shape of the dropdown, defining corner radius.
maxHeight Dp 300.dp Maximum height of the dropdown.
dropdownShadow DropdownShadow DropdownShadow(...) Configuration for the dropdown's shadow, including its shape and elevation.
horizontalPadding Dp 30.dp Horizontal padding inside the dropdown.
headerPlaceholder @Composable { Text(...) } Composable function for the dropdown's header placeholder.
withItemSelection Boolean true Indicates if item selection is enabled.
separationSpace Int 20 Space in pixels between the header and dropdown content.
toggleIcon ToggleIcon ToggleIcon() Configuration for the dropdown toggle icon.
itemSeparator DropdownItemSeparator DropdownItemSeparator() Configuration for separators between dropdown items.
emptySearchPlaceholder @Composable { EmptySearchPlaceholder() } Composable function displayed when no search results are found.
selectItemActionListener SelectActionListener<T> object : SelectActionListener<T> { ... } Listener for handling item selection actions in the dropdown.

ItemContentConfig Guide

The ItemContentConfig class (and its subtypes) allows you to configure how items in your dropdown are displayed. Depending on your use case, you can choose:

Single Item Selection – Only one item can be chosen. Multi-Item Selection – Multiple items can be chosen at once. Within each selection mode, there are two approaches to rendering items:

Default Content: Use a predefined layout with minimal setup. Custom Content: Fully control the composable layout of your items (and optionally the header). Below, you’ll find an overview of each approach in a format similar to the one shown for single-item usage.

Single Item Selection

Default Content

If you want a quick, predefined appearance (title, optional subtitle, and optional icon), you can pass a DefaultDropdownItem to a Default configuration. This is the easiest way to get started—just map the fields (e.g., title, subtitle) to your data’s properties.

val defaultConfig = SingleItemContentConfig.Default(
    defaultItem = DefaultDropdownItem(
        title = Person::name,
        subtitle = Person::job,
        withIcon = true
    )
)

Default Content Demo

Tip: You can hide the subtitle or the icon if you don’t need them by simply not providing those properties.

Custom Content

For maximum flexibility, use Custom. You’ll define a composable function for the content (how each item appears) and optionally a separate header layout (how the selected item is shown in the closed dropdown state).

val customConfig = SingleItemContentConfig.Custom(
    content = { person, _ ->
        // Define each item's row layout here
    },
    header = { person, _ ->
        // Define how to show the selected item in the header
    }
)

Key Point: If you omit the header parameter, it will use the same composable as content. This is perfect when you want both the dropdown items and the header to look the same.

Multi-Item Selection

Default Content (Multi)

Multi-selection also supports a Default approach. You can still provide something like a DefaultDropdownItem for consistency, but with multiple selections in mind. Additionally, you can tweak multi-selection options—such as the maximum number of items a user can select or whether to show a built-in checkbox.

val multipleDefaultConfig = MultipleItemContentConfig.Default(
    defaultItemCustomization = DefaultDropdownItem(
        title = Person::name,
        subtitle = Person::job,
        withIcon = true
    ),
    options = MultipleItemOptions(
        selectionMaxCount = 3,       // For example, limit to 3 selections
        useDefaultSelector = true    // Enable built-in checkboxes/icons
    )
)

Info: This gives you a quick setup where each selected item is managed automatically, and the dropdown shows a checkbox or icon by default.

Custom Content (Multi)

When you need full control over each item’s layout (including how you indicate “selected” vs. “not selected”), as well as how selected items appear in the header, choose Custom.

val multipleCustomConfig = MultipleItemContentConfig.Custom(
    content = { person, isSelected, multipleSelectActionListener ->
        // Define how each item row should look,
        // and call `onSelect` or `onDeselect` on click.
    },
    header = { person, selectedPerson, removeItemListener ->
        // Define how each selected item appears
        // in the header (e.g. chips or horizontal list).
    },
    options = MultipleItemOptions(
        selectionMaxCount = 5,
        useDefaultSelector = false
    )
)

You receive isSelected for each item, so you can visually reflect the selection state.

The multipleSelectActionListener helps you handle toggling (select/deselect) with a simple function call.

The header composable is called for each selected item if you want to display them (like chips or icons) above the list. Extras: MultipleItemOptions For multi-selection specifically, the options parameter lets you control various behaviors:

selectionMaxCount: Prevents users from selecting more than a certain number of items. useDefaultSelector: Adds a built-in checkbox or icon next to each item. defaultSelectorPosition: Positions that icon on the start or end of the item row. defaultCheckboxParams: Styles the checkbox if useDefaultSelector is true.

Upcoming Features

Here's what's coming next:

🔜 Animations

If you have suggestions or feature requests, feel free to open an issue or contribute to the repository.

🤝 Contributing

Contributions, issues and feature requests are welcome.
Feel free to check [issues page] if you want to contribute.

Author

👤 Mejdi Hafiane

Show your support

Please ⭐️ this repository if this project helped you!

📝 License

Copyright © 2019 Mejdi Hafiane.
This project is MIT licensed.