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")
}
/* 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)),
),
)
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. |
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. |
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.
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
)
)
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-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.
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.
Here's what's coming next:
If you have suggestions or feature requests, feel free to open an issue or contribute to the repository.
Contributions, issues and feature requests are welcome.
Feel free to check [issues page] if you want to contribute.
👤 Mejdi Hafiane
- profile: @MejdiHafiane
Please ⭐️ this repository if this project helped you!
Copyright © 2019 Mejdi Hafiane.
This project is MIT licensed.