It's been a moment since the last Compose Unstyled version update. There have been quite a few releases since then, but I never sent out any updates for it.
To be really honest, I just wanted to just show off the new interactive demos we can now use on the website so expect more immersive blog posts and documentation on Composables.
Here is what changed since the last update:
- New Tooltip Component added – create informational tooltips with keyboard, mouse, and touch support.
- Custom Detent support for sheets added – dynamically control sheet detents.
- New Stack component added – flexible layout composable for horizontal or vertical arrangements.
- New currentWindowContainerSize() function added – get the current window size for responsive layouts.
- Stateful TextField added – support for Compose's new stateful text fields.
New Tooltip Component added
The new Tooltip primitive component allows you to create informational tooltips for your apps. It is automatically displayed when you long-press its trigger, mouse over it or when the trigger is focused.
The Unstyled Tooltip is a complete rewrite of Tooltips in Compose and does not use the standard Compose Tooltip API. This is because the Compose Tooltip API does not work with keyboards and mouse as it is modal.
The Unstyled Tooltip is not modal and therefore does not steal focus or block pointer events.
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@Composable
fun ArrowUp(modifier: Modifier = Modifier, color: Color) {
Canvas(modifier = modifier.size(8.dp, 4.dp)) {
val path = Path().apply {
moveTo(size.width / 2f, 0f)
lineTo(0f, size.height)
lineTo(size.width, size.height)
close()
}
drawPath(path, color = color)
}
}
@Composable
fun TooltipExample() {
Tooltip(
placement = RelativeAlignment.TopCenter,
panel = {
TooltipPanel(
modifier = Modifier.zIndex(15f),
enter = slideInVertically(tween(150), initialOffsetY = { (it * 0.25).toInt() }) +
scaleIn(
animationSpec = tween(150),
transformOrigin = TransformOrigin(0.5f, 1f),
initialScale = 0.65f
) + fadeIn(tween(150)),
exit = fadeOut(tween(250)),
arrow = { direction ->
val degrees = when (direction) {
TooltipArrowDirection.Up -> 0f
TooltipArrowDirection.Down -> 180f
TooltipArrowDirection.Left -> 90f
TooltipArrowDirection.Right -> 270f
}
ArrowUp(Modifier.rotate(degrees), Color.Black.copy(0.8f))
}
) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(100))
.background(Color.Black.copy(0.8f))
.padding(vertical = 8.dp, horizontal = 12.dp),
) {
Text("This is a tooltip", color = Color.White)
}
}
}
) {
Button(
onClick = { },
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
backgroundColor = Color.White,
shape = RoundedCornerShape(8.dp),
modifier = Modifier.border(1.dp, Color(0xFFE5E7EB), RoundedCornerShape(8.dp))
) {
Text("Hover me")
}
}
}
Checkout the Tooltip documentation for more details.
Custom Detent support for sheets added
You can now dynamically control the detents of your sheets by using the new detents setter on the state class.
If the detent in which the sheet is rested at does not exist anymore, then it will be animated to the closest detent available.
For more details, checkout the Bottom Sheet documentation.
New Stack component added
The new Stack component is a flexible layout composable that can arrange its children either horizontally or
vertically. You can control using the orientation parameter.
This is incredibly handy when you are building responsive apps. You can use this with the new [currentWindowContainerSize()] function to get the size of the container and change the orientation accordingly.
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
import com.composeunstyled.Stack
import com.composeunstyled.StackOrientation
import com.composeunstyled.currentWindowContainerSize
var orientation by remember { mutableStateOf(StackOrientation.Horizontal) }
Stack(
orientation = orientation,
spacing = 16.dp
) {
Box(/*...*/) {
Text("0")
}
Box(/*...*/) {
Text("1")
}
Box(/*...*/) {
Text("2")
}
}
For more details, checkout the Stack documentation.
New currentWindowContainerSize() fun added
A new utility function that returns the size of the window in which your Composable is rendered on.
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
HINT: Resize your browser's width to see the size changing.
import com.composeunstyled.currentWindowContainerSize
val containerSize = currentWindowContainerSize()
Stateful TextField added
Compose has recently introduced new versions of BasicTextField which are stateful. It is recommended to use those over
the original stateless overload, as they fix a bug of issues with soft-keyboard glitches in various languages.
TextFields in Compose Unstyled now support the same state objects using the rememberTextFieldState() function.
For more details, head over the TextField docs.
That's all for this update. Catch you in the next one.
– Alex

