sp: what is it, scalable pixels for text in Android

Author: IT Sectr Published: 2026-02-25 Reading time: 9 min

sp — Scale-independent Pixels, a text measurement unit in Android that accounts for the device's font size settings. Unlike dp, sp scales with the system font size, ensuring interface accessibility. This article explains the difference between sp and dp, shows how to set textSize in XML and Kotlin, and reveals best practices for working with typography in Android.

Key Takeaways

  • sp — a unit for text that scales with the user's system font settings
  • dp — a unit for element dimensions, does not respond to font size changes
  • Difference between sp and dp: sp = dp × scaleFactor, where scaleFactor depends on font settings
  • textSize in XML is set via sp: android:textSize="16sp"
  • Material Design recommends a typography range from 12sp to 34sp for headings

What is sp in Android?

sp (scale-independent pixel) — a font size measurement unit in Android that automatically scales according to the user's system settings. When the device owner increases the font size in settings, all elements with sp values grow proportionally. This ensures accessibility of the interface for people with visual impairments.

The basic ratio: 1 sp = 1 dp at the standard font scale of 1.0 (normal). If the user sets the font to Large (1.15×), 16 sp becomes 18.4 physical pixels. At Small font size (0.85×), the same 16 sp becomes 13.6 px. The scaling mechanism is managed through Settings.System.FONT_SCALE at the Android Framework level.

According to Google Material Design Guidelines, text should be specified exclusively in sp. The exception is fixed labels in components where size is critical for layout (e.g., text inside fixed-height buttons). In such cases, it is recommended to use dp with manual accessibility control.

sp vs dp: Key Differences

The difference between sp and dp is one of the most common topics in Android developer interviews and real code reviews. Both units are tied to density-independent pixels (160 dpi = 1 dp = 1 px on mdpi screens), but behave differently when the system font size changes.

Characteristicspdp
PurposeText sizeElement dimensions, padding, width, height
Font scalingYes (scale factor)No
Density scalingYesYes
Setting APIandroid:textSizeandroid:layout_width, layout_height, padding, margin
Material Design Tokentypescalespacing, sizing

In practice, a common mistake is using dp for text. If text is set in dp, it does not scale when the font size increases, making the interface inaccessible for users with poor eyesight. The reverse mistake is using sp for button height or padding: when the font size increases, the button may "inflate," breaking the layout.

How sp Scaling Works

sp scaling is implemented at the Android Framework level in the TypedValue class. The conversion formula is: sp = dp × scaledDensity, where scaledDensity is a scaling factor that accounts for both screen density and the user's font size setting.

kotlin
// Programmatic retrieval of scaledDensity in Kotlin
val scaledDensity = with(context.resources) {
    displayMetrics.scaledDensity
}

// Converting sp to px
fun spToPx(sp: Float, context: Context): Float {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_SP,
        sp,
        context.resources.displayMetrics
    )
}

// Converting px to sp
fun pxToSp(px: Float, context: Context): Float {
    return px / context.resources.displayMetrics.scaledDensity
}

The TypedValue.applyDimension method is the only correct way to convert sp to pixels at runtime. Direct multiplication by scaledDensity is less reliable as it does not handle edge cases (zero values, overflow). scaledDensity changes when font settings are modified via Settings > Display > Font size.

Scaling Factors

Android provides five preset font scale levels: Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.3×), and an additional Very Large level (>1.3×) in Android 14+. Device manufacturers (Samsung, Xiaomi) add their own levels — up to 2.0×. The minimum text size in sp never guarantees a fixed number of pixels.

Using sp in XML Layouts

In XML layouts, sp is used exclusively in the android:textSize attribute. All other dimensions — width, height, padding, margin, elevation — are set in dp. The rule is simple: if the element displays text, its size is in sp; if the element defines geometry, the size is in dp.

Basic textSize Example in XML

xml
<!-- TextView layout with textSize in sp -->
<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    android:textSize="16sp"
    android:padding="12dp"
    android:lineSpacingExtra="4dp" />

<!-- Using dimens resources -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="@dimen/text_body_large" />

It is recommended to extract text sizes into a dimens.xml file. This simplifies typography maintenance, allows overriding sizes for different screen configurations, and ensures consistency throughout the application.

dimens.xml with Typographic Tokens

xml
<!-- res/values/dimens.xml -->
<resources>
    <!-- Material Design Type Scale -->
    <dimen name="text_display_large">34sp</dimen>
    <dimen name="text_display_medium">28sp</dimen>
    <dimen name="text_headline_large">24sp</dimen>
    <dimen name="text_headline_medium">20sp</dimen>
    <dimen name="text_title_large">18sp</dimen>
    <dimen name="text_body_large">16sp</dimen>
    <dimen name="text_body_medium">14sp</dimen>
    <dimen name="text_label_large">14sp</dimen>
    <dimen name="text_label_small">11sp</dimen>
</resources>

Material Design Type Scale includes 13 size levels — from 11sp for small labels to 57sp for large display headings. Android projects typically use 8–10 levels. All values should be multiples of 1sp — fractional values (15.5sp) degrade rendering due to subpixel positioning.

Configuring Typography via Kotlin

In modern Android development, text is rarely set directly via textSize in sp. Instead, the MaterialTheme.typography system is used, where each style is predefined and includes size, weight, line height, and letter-spacing.

kotlin
// Custom typography via Typography API
val AppTypography = Typography(
    displayLarge = TextStyle(
        fontWeight = FontWeight.Normal,
        fontSize = 34.sp,
        lineHeight = 40.sp,
        letterSpacing = 0.sp
    ),
    headlineLarge = TextStyle(
        fontWeight = FontWeight.SemiBold,
        fontSize = 24.sp,
        lineHeight = 32.sp
    ),
    titleLarge = TextStyle(
        fontWeight = FontWeight.Medium,
        fontSize = 18.sp,
        lineHeight = 24.sp
    ),
    bodyLarge = TextStyle(
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.5.sp
    ),
    labelSmall = TextStyle(
        fontWeight = FontWeight.Medium,
        fontSize = 11.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.5.sp
    )
)

The extension function .sp in Jetpack Compose automatically translates to scale-independent pixels. When the system font size changes, Compose recalculates fontSize, lineHeight, and spacing according to the new scaledDensity. TextUnit (the class representing sp) guarantees that text scales while padding does not.

sp in Jetpack Compose

In Jetpack Compose, sp is represented by the TextUnit type, which cannot be accidentally used for element dimensions. The Kotlin compiler will throw an error if TextUnit is passed where Dp is expected. This eliminates an entire class of bugs related to incorrect scaling.

kotlin
// TextUnit in Compose — safe work with sp
@Composable
fun ArticleCard(title: String, description: String) {
    Card(modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp)
    ) {
        Text(
            text = title,
            style = MaterialTheme.typography.titleLarge
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(
            text = description,
            style = MaterialTheme.typography.bodyMedium
        )
    }
}

// Explicitly setting fontSize in sp
Text(
    text = "Custom size",
    fontSize = 20.sp,
    fontWeight = FontWeight.Bold,
    color = MaterialTheme.colorScheme.primary
)

Compose has no direct equivalent of the XML attribute android:textSize — text size is set via TextStyle.fontSize. The MaterialTheme.typography system provides predefined styles that correspond to the Material Design Type Scale. If a custom size is needed, the literal 20.sp is used — the language guarantees that this is TextUnit, not Dp.

Best Practices for Working with sp

Proper use of sp is the foundation of an accessible Android application. Below are rules based on Google Material Design and Android Developers Guide recommendations.

  • Always use sp for text — never set textSize in dp or px, otherwise users with enlarged fonts will not be able to read the interface
  • Use dp for containers — button height, padding, and card width should be in dp, otherwise elements may overlap with large fonts
  • Extract sizes into dimens.xml — centralized storage of typographic tokens simplifies refactoring and dark theme support
  • Do not use sp smaller than 12sp — smaller text becomes unreadable on high PPI devices and at standard font sizes
  • Test at maximum font scale — enable the largest font in device settings and verify that the interface does not break

The main accessibility rule: the user should be able to increase the font size without losing functionality. If the application works correctly at a font scale of 1.3×, it will pass basic accessibility tests. Google Play may reject the application if textSize is set in dp and the interface does not scale.

Frequently Asked Questions

How is sp different from dp?

sp (scale-independent pixel) scales when the system font size changes, while dp does not. sp is used only for text, dp for all other element dimensions. Conversion factor: sp = dp × FONT_SCALE.

Can sp be used for padding?

No. Padding, button height, and card width should be set in dp. Using sp for padding causes elements to grow unnaturally when the font size increases and may extend beyond screen boundaries.

How to verify that the app works correctly with sp?

Open Settings > Display > Font size and set it to the maximum value (Largest). Launch the application and check that all text is readable, elements do not overlap, and buttons do not extend beyond the screen boundaries. For automation, use Espresso with UiAutomator.

What is the minimum allowed text size in sp?

Material Design recommends a minimum size of 11sp for labelSmall. For body text — from 14sp (bodyMedium) to 16sp (bodyLarge). Sizes smaller than 11sp are not recommended as they become unreadable on devices with high pixel density.

What happens if textSize is set in dp?

The text will be displayed at a fixed size regardless of system font settings. Users with enlarged fonts will not be able to read such text comfortably. This violates WCAG accessibility requirements and may cause the application to be rejected from Google Play.

Summary

  • sp — font measurement unit in Android that scales with user settings via FONT_SCALE
  • dp — unit for element dimensions that does not respond to font size changes
  • textSize in XML is set via android:textSize="16sp", all other dimensions in dp
  • MaterialTheme.typography in Jetpack Compose uses TextUnit (.sp) for type safety
  • dimens.xml — centralized storage of typographic tokens for consistency
  • Minimum size for text — 11sp, recommended for body — 14–16sp
  • Testing at maximum font scale — a mandatory step for accessibility verification

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also