# EmojiSlider: a Compose slider that throws emoji at the user

> EmojiSlider is a Compose Multiplatform slider whose thumb is an emoji and whose selection sprays floating reactions, running on Android, desktop and web from one Kotlin library. It is playful by design and has some sharp edges, from a locked value after the first gesture to emoji that vanish when a parent clips its bounds.

**bernaferrari/EmojiSlider** — 🤯 A slider widget rich in emoji and highly customisable.

- Repository: https://github.com/bernaferrari/EmojiSlider
- Website: https://bernaferrari.github.io/EmojiSlider/
- Stars: 617 · Forks: 43
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/bernaferrari-emojislider

## A rating control that reacts to the drag

EmojiSlider is a slider widget whose thumb is an emoji and whose drag produces a shower of small emoji reactions. The README describes it as a Compose Multiplatform slider with an emoji thumb and floating reactions, for Android, desktop and web.

The use case it serves is a mood or rating input, the kind of thing that appears at the end of an onboarding flow or under a review. The point is that the interaction carries feedback beyond the value itself: the thumb is a face that travels along the track, and the act of choosing something throws a small celebration onto the screen.

That framing also defines the boundaries. This is a controlled Compose component, not a native Android View, so it plugs into Compose code rather than into XML layouts or View based interop. The library is written in Kotlin, the primary language of the repository, and the API is expressed entirely in composable parameters.

For a serious instrument like a price range or a brightness curve, the same API would work but the aesthetics fight the purpose. A slider that throws emoji at the user communicates playfulness, not precision, and precision seekers will find that the first completed gesture locks the value unless they change the behaviour.

## Controlled value, explicit behaviour, four configuration objects

The parameter list is short and the design is conventional for Compose. `value` and `onValueChange` give controlled progress in the range 0f to 1f, which means the caller owns the state, exactly as with the platform sliders.

The other parameters group into small value classes. `emoji` sets the thumb and particle glyph. `colors` takes an `EmojiSliderColors` with start, end, track and active brush. `behavior` takes an `EmojiSliderBehavior` covering seekable, reselection, direction and the average, result and tooltip options. `sizes` takes an `EmojiSliderSizes` for track, thumb, height, inset and particle minimum and maximum.

Two parameters stand apart because they are about presentation rather than control. `averageProgress` places a marker for an average value, and `resultBitmap` allows an optional image after a one-shot selection, which is the hook for showing a summary screen once the user has committed.

The one default worth knowing before you lay out a screen is `sizes.trackInset`, which defaults to half the thumb so the emoji stays on the canvas. That is a thoughtful default, because a thumb centred on a full width track would be clipped at both ends, but it also means the usable track is shorter than the width of the container. Passing 0.dp gives an edge to edge track, at the cost of the emoji overhang at the extremes.

## Adding the library and dropping in a first slider

The install step is one Gradle dependency:

```kotlin
implementation("io.github.bernaferrari:emojislider:1.0.0")
```

The basic usage is a composable function that holds the value with remember and mutableFloatStateOf, then passes it to the slider, along with the imports for the runtime state, the graphics colour type and the two slider classes from the `com.bernaferrari.emojislider` package:

```kotlin
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import com.bernaferrari.emojislider.EmojiSlider
import com.bernaferrari.emojislider.EmojiSliderColors
```

Inside the composable, the state is declared with `var value by remember { mutableFloatStateOf(0.5f) }` and the slider is called with `value = value`, `onValueChange = { value = it }`, an `emoji` glyph, and a `colors` argument of `EmojiSliderColors` with `start` and `end` entries. The gradient runs from a violet `Color(0xFF7C3AED)` at the start to a pink `Color(0xFFDB2777)` at the end.

What you should see on screen is a track shaded from violet to pink, with the chosen glyph sitting on the thumb, and a burst of small glyphs when the value changes.

Two behaviour changes are worth copying before you ship. By default the first completed gesture locks the value and can reveal the average, so if the slider is supposed to behave like a normal one you turn reselection on:

```kotlin
EmojiSlider(
    value = value,
    onValueChange = { value = it },
    behavior = EmojiSliderBehavior(allowReselection = true),
)
```

And if you want the average marker and a tooltip once a value has been chosen, that is also a behaviour setting:

```kotlin
EmojiSlider(
    value = value,
    onValueChange = { value = it },
    averageProgress = 0.72f,
    behavior = EmojiSliderBehavior(
        displayAverage = true,
        displayTooltip = true,
        tooltipText = "Average value",
    ),
)
```

## The particle overlay and the clipping problem it solves

The floating reactions are the interesting engineering problem in this library, and the README explains the failure mode plainly: cards and scroll containers clip the fly-away emoji.

The fix is to lift the particle drawing out of the slider and into a shared overlay that wraps the screen:

```kotlin
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import com.bernaferrari.emojislider.EmojiSlider
import com.bernaferrari.emojislider.EmojiSliderParticleSystem

@Composable
fun Screen() {
    EmojiSliderParticleSystem(modifier = Modifier.fillMaxSize()) {
        EmojiSlider(
            value = value,
            onValueChange = { value = it },
        )
    }
}
```

`EmojiSliderParticleSystem` is a container that fills the available space and hosts the slider inside it, so particles can travel beyond the slider's own bounds and across the whole screen.

The fallback is documented too. Without the wrap, the slider uses a local overlay, and the README says that is fine when the slider has enough space and is not clipped. So the wrapper is opt in and only needed in the layout shapes that clip.

This is a real trade-off in the API design. The simple case needs one component and no thinking about z order or overlay hosting. The interesting case, where the slider sits inside a card, needs the screen to be restructured around a particle system, which is a bigger change than swapping a component.

## Where the playful slider stops being appropriate

The most concrete limitation is the locking behaviour. By default the first completed gesture locks the value, so a user who mis-drags and wants to correct the number has to go through the reselection option rather than simply dragging again. A control where a second attempt behaves differently from the first is a usability question, not just a default value, and it applies to any survey or rating screen where precision matters to the person filling it in.

The second limitation is layout coupling. The particle system requirement means the component is not drop in inside arbitrary containers, and the default track inset means the visual track does not span the width you measured.

The third is scope of platform. The library is Compose Multiplatform and the README names Android, desktop and web. Other targets are not mentioned, so a project that also has to run somewhere else would need another implementation of the same design.

One documentation gap is worth flagging: the README does not describe accessibility behaviour, so a control that is visually a coloured track with a decorative glyph on it raises the question of what a screen reader announces and how keyboard and switch input reach the value. The API is controlled, which helps, but the documented surface says nothing about it.

## Repository shape, licence and the absence of releases

The tree follows the multiplatform library convention. The `emojislider/` directory holds the library module, `androidApp/` is the Android application, `example/` contains a sample build file and source, and `docs/` holds documentation. Gradle wiring sits at the root with build.gradle.kts, settings.gradle.kts, gradle.properties and the wrapper scripts, and there is an assets directory for the images used in the README, including the header image.

The project is licensed under Apache-2.0 with a LICENSE file at the top level. Apache-2.0 is permissive and allows commercial use and modification, with the conditions of preserving the licence and notice files and stating changes.

The versioning story is thin in a way that matters for a library. The repository has no GitHub releases, yet the README instructs you to depend on a specific published version, `1.0.0`. The repository is not archived and the last push was on 2026-10-12, so work is clearly still happening on the tree even though the published coordinate is a single fixed version.

There is also a live web example hosted at the project homepage, which is the fastest way to see the interaction before writing any code, and it demonstrates the multiplatform claim by running in a browser rather than on a device.

## Conclusion

Adopt EmojiSlider when you are building a Compose Multiplatform surface that wants a rating control with personality, on Android, desktop or web, and you can live with a value that locks after the first completed gesture unless you enable allowReselection. Do not adopt it for a form that needs precise numeric entry, a slider that must live inside a clipping card without extra work, or a component library that must avoid emoji in its output, since the particle overlay and the default thumb glyph are part of the design. Before integrating, check the two defaults that surprise people: sizes.trackInset defaults to half the thumb so the emoji stays on canvas, and the default first completed gesture locks the value.

## FAQ

### How do I add EmojiSlider to a Compose project?

Add the Gradle dependency `implementation("io.github.bernaferrari:emojislider:1.0.0")` and use the `EmojiSlider` composable with a `value` and an `onValueChange` callback. The library targets Compose Multiplatform for Android, desktop and web.

### Why do the floating emoji disappear when EmojiSlider is inside a card?

Cards and scroll containers clip the fly-away emoji. Wrap the screen in `EmojiSliderParticleSystem` so the particles draw in a shared overlay, or leave the slider in a space that has room and is not clipped.

### How do I make EmojiSlider behave like a normal slider?

By default the first completed gesture locks the value. Pass `behavior = EmojiSliderBehavior(allowReselection = true)` to let the user change the value again afterwards.

### How do I show an average marker and a tooltip on EmojiSlider?

Set `averageProgress` to the position of the average and enable `displayAverage` and `displayTooltip` in `EmojiSliderBehavior`, with `tooltipText` for the label. The optional `resultBitmap` parameter adds an image after a one-shot selection.

### Can I change the colors and sizes of EmojiSlider?

Yes. `colors` takes an `EmojiSliderColors` with start, end, track and active brush values, and `sizes` takes an `EmojiSliderSizes` for track, thumb, height, inset and particle minimum and maximum. `sizes.trackInset` defaults to half the thumb so the emoji stays on canvas.

## Sources

- [bernaferrari/EmojiSlider on GitHub](https://github.com/bernaferrari/EmojiSlider)
- [Issues](https://github.com/bernaferrari/EmojiSlider/issues)
- [License: Apache-2.0](https://github.com/bernaferrari/EmojiSlider/blob/main/LICENSE)
- [Project website](https://bernaferrari.github.io/EmojiSlider/)
- [README](https://github.com/bernaferrari/EmojiSlider/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bernaferrari-emojislider
