Android
button styling
user interface
border customization
mobile development

Android - border for button

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Adding borders to Android buttons is usually done with drawable resources or Material component stroke attributes. The right method depends on whether your UI uses classic Button widgets or MaterialButton. A production-ready border style also handles pressed, disabled, and dark-theme states consistently.

Border With XML Shape Drawable

A straightforward approach is creating a drawable with transparent fill and stroke.

Create res/drawable/button_border.xml.

xml
1<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
2    <solid android:color="@android:color/transparent" />
3    <stroke android:width="2dp" android:color="@color/primary" />
4    <corners android:radius="8dp" />
5    <padding android:left="12dp" android:top="8dp" android:right="12dp" android:bottom="8dp" />
6</shape>

Apply in layout:

xml
1<Button
2    android:id="@+id/saveButton"
3    android:layout_width="wrap_content"
4    android:layout_height="wrap_content"
5    android:text="Save"
6    android:background="@drawable/button_border" />

This works well for many legacy or simple layouts.

Preferred Material Approach

If your app uses Material Components, prefer MaterialButton stroke properties.

xml
1<com.google.android.material.button.MaterialButton
2    android:id="@+id/actionButton"
3    android:layout_width="wrap_content"
4    android:layout_height="wrap_content"
5    android:text="Continue"
6    app:strokeColor="@color/primary"
7    app:strokeWidth="2dp"
8    app:cornerRadius="10dp" />

This integrates better with ripple, elevation, and theme overlays.

State-Aware Border Colors

Buttons should visually communicate pressed and disabled states. Use a color selector for stroke color.

Create res/color/button_stroke_selector.xml.

xml
1<selector xmlns:android="http://schemas.android.com/apk/res/android">
2    <item android:state_enabled="false" android:color="@color/gray_400" />
3    <item android:state_pressed="true" android:color="@color/primary_dark" />
4    <item android:color="@color/primary" />
5</selector>

Then set app:strokeColor to this selector for MaterialButton.

Programmatic Border Updates

When theme or state changes dynamically, update border in Kotlin.

kotlin
1import com.google.android.material.button.MaterialButton
2
3fun applyOutline(button: MaterialButton, strokeWidthPx: Int, strokeColorRes: Int) {
4    button.strokeWidth = strokeWidthPx
5    button.setStrokeColorResource(strokeColorRes)
6    button.cornerRadius = 16
7}

Use resource-driven values, not hardcoded pixels.

Dark Mode and Contrast

A border visible in light theme may disappear in dark theme. Define semantic colors for both modes and verify contrast with surrounding surfaces. Do not rely on one static hex value unless it is part of a controlled design token system.

Test outlined buttons in:

  • light theme
  • dark theme
  • disabled state
  • high contrast accessibility mode

Layout and Rendering Issues

If border appears clipped or missing, check:

  • parent container clipping behavior
  • button minimum height and padding
  • background override from style or theme
  • corner radius too large for button size

Small layout constraints can make stroke invisible even when drawable is correct.

Accessibility and UX Considerations

Border should not be the only indicator of state. Combine border changes with text color, elevation, or icon feedback. Ensure touch target still meets recommended size for usability. Outlined style should remain clear for users with low vision.

Reusable Design System Styles

Instead of one-off border drawables per screen, define reusable button styles in themes. This keeps border width, radius, and color behavior consistent across app modules.

A centralized style also makes redesign and theme updates safer because one change propagates predictably.

Quick Verification Checklist

Before shipping, verify outlined buttons on multiple devices and densities. Check pressed, focused, and disabled states in both light and dark themes. Confirm border remains visible when dynamic text size increases and when localization expands button label length.

Common Pitfalls

A common pitfall is mixing custom drawable backgrounds with Material styles and losing expected ripple behavior. Another is forgetting disabled and pressed state border definitions. Teams often hardcode color values and break dark-mode contrast. Border clipping from tight layout constraints is also frequent. Finally, accessibility is overlooked when border is treated as the only state cue.

Summary

  • Use shape drawables for classic buttons and simple border needs.
  • Prefer MaterialButton stroke APIs in Material-based apps.
  • Define state-aware border colors for pressed and disabled behavior.
  • Validate border visibility across light and dark themes.
  • Use reusable style definitions for consistent UI.
  • Pair border styling with accessibility-friendly state feedback.

Course illustration
Course illustration

All Rights Reserved.