What You Will Build

Neon-styled UI elements that pulse with a glow effect: a neon text heading, a glowing circle with multiple glow rings, and a card with an animated neon border. All elements pulse between dim and bright using an infinite transition. The result is a cyberpunk / synthwave aesthetic.

Why This Pattern Matters

Neon glow effects are popular in gaming apps, music players, and dark-themed dashboards. This pattern teaches you drawBehind for custom drawing behind composables, multiple concentric glow rings via loop-based drawing, and animated alpha for the pulsing effect.

Step 1: Infinite Pulsing Animations

@Composable
fun NeonGlowScreen() {
    val infiniteTransition = rememberInfiniteTransition(
        label = "neon"
    )

    // Pulsing alpha for glow intensity
    val glowAlpha by infiniteTransition.animateFloat(
        initialValue = 0.3f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(1500),
            repeatMode = RepeatMode.Reverse
        ),
        label = "glow"
    )

    // Hue shift for color cycling (optional)
    val hueShift by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 360f,
        animationSpec = infiniteRepeatable(
            animation = tween(5000, easing = LinearEasing)
        ),
        label = "hue"
    )

Step 2: Neon Text with drawBehind Glow

Text(
    "Neon Glow",
    fontSize = 36.sp,
    fontWeight = FontWeight.Bold,
    color = Color(0xFF00FF88).copy(alpha = glowAlpha),
    modifier = Modifier.drawBehind {
        drawRect(
            color = Color(0xFF00FF88)
                .copy(alpha = glowAlpha * 0.3f),
            style = Stroke(width = 4f)
        )
    }
)

Step 3: Glowing Circle with Multiple Rings

Box(
    modifier = Modifier
        .size(150.dp)
        .drawBehind {
            // Draw 3 concentric glow rings
            for (i in 1..3) {
                drawCircle(
                    color = Color(0xFF00BFFF)
                        .copy(alpha = glowAlpha * (0.3f / i)),
                    radius = size.minDimension / 2 +
                        i * 20f
                )
            }
            // Inner bright circle
            drawCircle(
                color = Color(0xFF00BFFF)
                    .copy(alpha = glowAlpha)
            )
        }
)

Step 4: Neon Border Card

Card(
    modifier = Modifier.padding(horizontal = 40.dp),
    shape = RoundedCornerShape(16.dp),
    colors = CardDefaults.cardColors(
        containerColor = Color(0xFF1A1A2E)
    ),
    border = BorderStroke(
        2.dp,
        Color(0xFFFF00FF).copy(alpha = glowAlpha)
    )
) {
    Column(
        Modifier.padding(24.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("Neon Card",
            color = Color(0xFFFF00FF)
                .copy(alpha = glowAlpha),
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp)
        Text("Glowing effect",
            color = Color.White.copy(alpha = 0.7f))
    }
}

Tips and Pitfalls

  • Dark background is essential: Neon effects only work against dark backgrounds. Use Color(0xFF0A0A0A) or similar.
  • Glow ring math: Each ring has alpha = glowAlpha * (0.3f / i) where i increases. This creates a natural falloff from bright core to dim outer glow.
  • Performance: drawBehind is efficient because it draws directly on the Canvas without triggering recomposition. The animation only changes the alpha value.
  • True glow with blur: For a soft, realistic neon glow on API 31+, apply BlurEffect via graphicsLayer { renderEffect = ... } on a colored layer behind the text.

Min SDK: API 21+ with Compose 1.0+

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.