Skip to main content
IconButton provides clickable icon containers with various styling options including filled, outlined, elevated, and ghost variants. Perfect for toolbars, app bars, and compact action buttons.

Usage

import com.nomanr.lumo.ui.components.IconButton
import com.nomanr.lumo.ui.components.IconButtonVariant

IconButton(
    variant = IconButtonVariant.Primary,
    onClick = { /* Handle click */ }
) {
    Icon(Icons.Default.Add, "Add")
}

Variants

Primary Variants

// Filled primary button
IconButton(
    variant = IconButtonVariant.Primary,
    onClick = { }
) {
    Icon(Icons.Default.Edit, "Edit")
}

// Outlined primary button
IconButton(
    variant = IconButtonVariant.PrimaryOutlined,
    onClick = { }
) {
    Icon(Icons.Default.Edit, "Edit")
}

// Elevated primary button
IconButton(
    variant = IconButtonVariant.PrimaryElevated,
    onClick = { }
) {
    Icon(Icons.Default.Edit, "Edit")
}

// Ghost primary button (transparent)
IconButton(
    variant = IconButtonVariant.PrimaryGhost,
    onClick = { }
) {
    Icon(Icons.Default.Edit, "Edit")
}

Secondary Variants

// Filled secondary
IconButton(
    variant = IconButtonVariant.Secondary,
    onClick = { }
) {
    Icon(Icons.Default.Settings, "Settings")
}

// Outlined secondary
IconButton(
    variant = IconButtonVariant.SecondaryOutlined,
    onClick = { }
) {
    Icon(Icons.Default.Settings, "Settings")
}

// Elevated secondary
IconButton(
    variant = IconButtonVariant.SecondaryElevated,
    onClick = { }
) {
    Icon(Icons.Default.Settings, "Settings")
}

// Ghost secondary
IconButton(
    variant = IconButtonVariant.SecondaryGhost,
    onClick = { }
) {
    Icon(Icons.Default.Settings, "Settings")
}

Destructive Variants

For delete, remove, or other destructive actions:
// Filled destructive
IconButton(
    variant = IconButtonVariant.Destructive,
    onClick = { /* Delete action */ }
) {
    Icon(Icons.Default.Delete, "Delete")
}

// Outlined destructive
IconButton(
    variant = IconButtonVariant.DestructiveOutlined,
    onClick = { }
) {
    Icon(Icons.Default.Delete, "Delete")
}

// Elevated destructive
IconButton(
    variant = IconButtonVariant.DestructiveElevated,
    onClick = { }
) {
    Icon(Icons.Default.Delete, "Delete")
}

// Ghost destructive
IconButton(
    variant = IconButtonVariant.DestructiveGhost,
    onClick = { }
) {
    Icon(Icons.Default.Delete, "Delete")
}

Ghost Variant

Adapts to any background color:
CompositionLocalProvider(
    LocalContentColor provides contentColorFor(AppTheme.colors.background)
) {
    IconButton(
        variant = IconButtonVariant.Ghost,
        onClick = { }
    ) {
        Icon(Icons.Default.Menu, "Menu")
    }
}

Button Shapes

Square Shape (Default)

IconButton(
    variant = IconButtonVariant.Primary,
    shape = IconButtonDefaults.ButtonSquareShape, // RoundedCornerShape(12.dp)
    onClick = { }
) {
    Icon(Icons.Default.Star, "Favorite")
}

Circle Shape

IconButton(
    variant = IconButtonVariant.Primary,
    shape = IconButtonDefaults.ButtonCircleShape, // RoundedCornerShape(50%)
    onClick = { }
) {
    Icon(Icons.Default.Person, "Profile")
}

Custom Shape

IconButton(
    variant = IconButtonVariant.Primary,
    shape = RoundedCornerShape(8.dp),
    onClick = { }
) {
    Icon(Icons.Default.Notifications, "Notifications")
}

Button States

Enabled and Disabled

var isEnabled by remember { mutableStateOf(true) }

IconButton(
    variant = IconButtonVariant.Primary,
    enabled = isEnabled,
    onClick = { /* Only called when enabled */ }
) {
    Icon(Icons.Default.Send, "Send")
}

Loading State

var isLoading by remember { mutableStateOf(false) }

IconButton(
    variant = IconButtonVariant.Primary,
    loading = isLoading,
    onClick = { 
        isLoading = true
        // Perform async operation
    }
) {
    if (isLoading) {
        CircularProgressIndicator(
            modifier = Modifier.size(20.dp),
            strokeWidth = 2.dp
        )
    } else {
        Icon(Icons.Default.Upload, "Upload")
    }
}

Parameters

modifier
Modifier
default:"Modifier"
Modifier for the icon button
enabled
Boolean
default:"true"
Whether the button is enabled and clickable
loading
Boolean
default:"false"
Whether the button is in a loading state
variant
IconButtonVariant
default:"IconButtonVariant.Primary"
The visual variant of the button (Primary, Secondary, Destructive, etc.)
shape
Shape
default:"IconButtonDefaults.ButtonSquareShape"
The shape of the button container
onClick
() -> Unit
default:"{}"
Callback when the button is clicked
contentPadding
PaddingValues
default:"PaddingValues(4.dp)"
Padding around the button content
interactionSource
MutableInteractionSource
Interaction source for tracking user interactions
content
@Composable () -> Unit
required
The icon content to display inside the button

Styling

Custom Padding

IconButton(
    variant = IconButtonVariant.Primary,
    contentPadding = PaddingValues(12.dp),
    onClick = { }
) {
    Icon(Icons.Default.Add, "Add")
}

With Modifier

IconButton(
    variant = IconButtonVariant.Primary,
    modifier = Modifier
        .size(56.dp)
        .padding(8.dp),
    onClick = { }
) {
    Icon(Icons.Default.Favorite, "Favorite")
}

Common Use Cases

App Bar Actions

TopBar(
    title = { Text("My App") },
    actions = {
        IconButton(
            variant = IconButtonVariant.Ghost,
            onClick = { /* Search */ }
        ) {
            Icon(Icons.Default.Search, "Search")
        }
        IconButton(
            variant = IconButtonVariant.Ghost,
            onClick = { /* More options */ }
        ) {
            Icon(Icons.Default.MoreVert, "More")
        }
    }
)

Floating Action Button Alternative

IconButton(
    variant = IconButtonVariant.PrimaryElevated,
    shape = IconButtonDefaults.ButtonCircleShape,
    modifier = Modifier.size(56.dp),
    onClick = { /* Add new item */ }
) {
    Icon(
        imageVector = Icons.Default.Add,
        contentDescription = "Add",
        modifier = Modifier.size(24.dp)
    )
}

Toggle Button

var isFavorite by remember { mutableStateOf(false) }

IconButton(
    variant = if (isFavorite) {
        IconButtonVariant.Primary
    } else {
        IconButtonVariant.PrimaryOutlined
    },
    shape = IconButtonDefaults.ButtonCircleShape,
    onClick = { isFavorite = !isFavorite }
) {
    Icon(
        imageVector = if (isFavorite) {
            Icons.Filled.Favorite
        } else {
            Icons.Outlined.FavoriteBorder
        },
        contentDescription = if (isFavorite) "Unfavorite" else "Favorite",
        tint = if (isFavorite) Color.Red else LocalContentColor.current
    )
}

List Item Actions

Row(
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp),
    horizontalArrangement = Arrangement.SpaceBetween,
    verticalAlignment = Alignment.CenterVertically
) {
    Text("Item Title")
    
    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        IconButton(
            variant = IconButtonVariant.SecondaryGhost,
            onClick = { /* Edit */ }
        ) {
            Icon(Icons.Default.Edit, "Edit")
        }
        
        IconButton(
            variant = IconButtonVariant.DestructiveGhost,
            onClick = { /* Delete */ }
        ) {
            Icon(Icons.Default.Delete, "Delete")
        }
    }
}

Media Controls

Row(
    horizontalArrangement = Arrangement.spacedBy(16.dp),
    verticalAlignment = Alignment.CenterVertically
) {
    IconButton(
        variant = IconButtonVariant.SecondaryGhost,
        onClick = { /* Previous */ }
    ) {
        Icon(Icons.Default.SkipPrevious, "Previous")
    }
    
    IconButton(
        variant = IconButtonVariant.Primary,
        shape = IconButtonDefaults.ButtonCircleShape,
        modifier = Modifier.size(56.dp),
        onClick = { /* Play/Pause */ }
    ) {
        Icon(
            imageVector = if (isPlaying) {
                Icons.Default.Pause
            } else {
                Icons.Default.PlayArrow
            },
            contentDescription = if (isPlaying) "Pause" else "Play",
            modifier = Modifier.size(28.dp)
        )
    }
    
    IconButton(
        variant = IconButtonVariant.SecondaryGhost,
        onClick = { /* Next */ }
    ) {
        Icon(Icons.Default.SkipNext, "Next")
    }
}

Defaults

  • Button Size: 44.dp (minimum touch target)
  • Content Padding: 4.dp
  • Square Shape: RoundedCornerShape(12.dp)
  • Circle Shape: RoundedCornerShape(50%)
  • Outline Width: 1.dp
  • Elevation (Elevated variants): 2.dp

Best Practices

  1. Touch Targets: Maintain 44dp minimum size for accessibility
  2. Content Descriptions: Always provide meaningful icon descriptions
  3. Variant Selection: Use appropriate variants for visual hierarchy
  4. Destructive Actions: Always use Destructive variants for delete/remove actions
  5. Loading States: Show loading indicators during async operations
  6. Disabled State: Clearly communicate when buttons are disabled
  7. Consistency: Use consistent icon sizes (typically 24dp)

Accessibility

  • Button role is automatically set for screen readers
  • Minimum 44dp touch target is enforced by default
  • Disabled state is properly communicated
  • Icon content descriptions are read by screen readers

Source Reference

See the full implementation in IconButton.kt:42-65 (component) and IconButton.kt:110-124 (variants).

Build docs developers (and LLMs) love