---
title: "TextFieldTextStyles"
description: "Provides access to the styles applied to the text within a TextFieldState."
type: "interface"
lastmod: "2026-05-20T01:13:53.388177Z"
---
## API Reference

> Source set: Common

```kotlin
interface TextFieldTextStyles
```

Provides access to the styles applied to the text within a [TextFieldState](/jetpack-compose/androidx.compose.foundation/foundation/classes/TextFieldState).

This interface provides a style query API similar to [TextFieldBuffer](/jetpack-compose/androidx.compose.foundation/foundation/classes/TextFieldBuffer), but returns immutable
data.

Use this interface when you only need to read the current text styles (e.g., to update a
formatting toolbar UI). If you need to mutate the text styles, use [TextFieldState.edit](/jetpack-compose/androidx.compose.foundation/foundation/classes/TextFieldState) and the
corresponding methods on [TextFieldBuffer](/jetpack-compose/androidx.compose.foundation/foundation/classes/TextFieldBuffer).

Do not use this interface to query styles within a [TextFieldBuffer](/jetpack-compose/androidx.compose.foundation/foundation/classes/TextFieldBuffer) edit block. The data
returned will not reflect any ongoing changes made to the buffer, as it only returns the
unupdated state from before the edit block began.

## Functions

### getSpanStyles

```kotlin
fun getSpanStyles(start: Int, end: Int): List<AnnotatedString.Range<SpanStyle>>
```

Returns a list of [AnnotatedString.Range](/jetpack-compose/androidx.compose.ui/ui-text/classes/AnnotatedString.Range)s representing the [SpanStyle](/jetpack-compose/androidx.compose.ui/ui-text/classes/SpanStyle)s that intersect with
the given range defined by `start` (inclusive) and `end` (exclusive).

Styles are returned in the same order they were originally added to the buffer.

A style intersects with the range if it overlaps with it at any point. For non-empty ranges,
this means `style.start < end` and `start < style.end`.

Example Query Range: `[5, 15)`

```
0    5    10   15   20   25
|----|----|----|----|----|    [---------)              Query Range [5, 15)

[-------------------)         Style [0, 20) (Contains query) -> Returned         [----)              Style [8, 12) (Inside query)   -> Returned
[----------)                  Style [0, 10) (Overlap start)  -> Returned
[----)                        Style [0, 5)  (Touching start) -> NOT Returned              [----------)   Style [15, 25)(Touching end)   -> NOT Returned
```

Example Collapsed Query: `[10, 10)`

```
0    5    10   15   20   25
|----|----|----|----|----|         |                   Query Range [10, 10)

[-------------------)         Style [0, 20) (Contains query) -> Returned
[---------)                   Style [0, 10) (Touching end)   -> NOT Returned         [----------)        Style [10, 20)(Touching start) -> Returned
```

#### Parameters

| | |
| --- | --- |
| start | The start index of the range to query, inclusive. |
| end | The end index of the range to query, exclusive. |

#### Returns

| | |
| --- | --- |
|  | A list of [AnnotatedString.Range](/jetpack-compose/androidx.compose.ui/ui-text/classes/AnnotatedString.Range)s representing the [SpanStyle](/jetpack-compose/androidx.compose.ui/ui-text/classes/SpanStyle)s overlapping with the queried range. |

### getParagraphStyles

```kotlin
fun getParagraphStyles(start: Int, end: Int): List<AnnotatedString.Range<ParagraphStyle>>
```

Returns a list of [AnnotatedString.Range](/jetpack-compose/androidx.compose.ui/ui-text/classes/AnnotatedString.Range)s representing the [ParagraphStyle](/jetpack-compose/androidx.compose.ui/ui-text/classes/ParagraphStyle)s that intersect
with the given range defined by `start` (inclusive) and `end` (exclusive).

Styles are returned in the same order they were originally added to the buffer.

A style intersects with the range if it overlaps with it at any point. For non-empty ranges,
this means `style.start < end` and `start < style.end`.

Example Query Range: `[5, 15)`

```
0    5    10   15   20   25
|----|----|----|----|----|    [---------)              Query Range [5, 15)

[-------------------)         Style [0, 20) (Contains query) -> Returned         [----)              Style [8, 12) (Inside query)   -> Returned
[----------)                  Style [0, 10) (Overlap start)  -> Returned
[----)                        Style [0, 5)  (Touching start) -> NOT Returned              [----------)   Style [15, 25)(Touching end)   -> NOT Returned
```

Example Collapsed Query: `[10, 10)`

```
0    5    10   15   20   25
|----|----|----|----|----|         |                   Query Range [10, 10)

[-------------------)         Style [0, 20) (Contains query) -> Returned
[---------)                   Style [0, 10) (Touching end)   -> NOT Returned         [----------)        Style [10, 20)(Touching start) -> Returned
```

#### Parameters

| | |
| --- | --- |
| start | The start index of the range to query, inclusive. |
| end | The end index of the range to query, exclusive. |

#### Returns

| | |
| --- | --- |
|  | A list of [AnnotatedString.Range](/jetpack-compose/androidx.compose.ui/ui-text/classes/AnnotatedString.Range)s representing the [ParagraphStyle](/jetpack-compose/androidx.compose.ui/ui-text/classes/ParagraphStyle)s overlapping with the queried range. |

## Code Examples

### BasicTextFieldTrackedRangeToggleBoldSample
```kotlin
@Composable
fun BasicTextFieldTrackedRangeToggleBoldSample() {
    // This sample demonstrates a realistic rich-text editor scenario using the `TrackedRange` and
    // `TextFieldTextStyles` APIs. It implements a "Toggle Bold" formatting function on the current
    // selection.
    // For simplicity, this sample keeps bold styles non-overlapping and contiguous, assuming they
    // are
    // applied exclusively through this method.
    val state = rememberTextFieldState("Hello World")
    // This derived state calculates whether the current selection is completely covered by
    // bold text styles. This ensures the "Bold" toggle button accurately reflects the
    // state of the selected text.
    val isSelection100PercentBold by derivedStateOf {
        val selection = state.selection
        if (selection.collapsed) {
            false
        } else {
            val spanStyles = state.textStyles.getSpanStyles(selection.min, selection.max)
            var boldCoverage = 0
            for (style in spanStyles) {
                if (style.item.fontWeight == FontWeight.Bold) {
                    val overlapStart = maxOf(style.start, selection.min)
                    val overlapEnd = minOf(style.end, selection.max)
                    if (overlapEnd > overlapStart) {
                        boldCoverage += (overlapEnd - overlapStart)
                    }
                }
            }
            boldCoverage == selection.length
        }
    }
    fun TextFieldBuffer.unBoldSelection() {
        // Query existing bold styles in the selection
        val intersectingStyles =
            getSpanStyles(selection.min, selection.max).filter {
                it.spanStyle.fontWeight == FontWeight.Bold
            }
        // We modify or remove existing styles to exclude the selected range
        for (style in intersectingStyles) {
            val range = style.textRange
            if (range.start >= selection.min && range.end <= selection.max) {
                // The style is fully inside the selection. Remove it.
                removeStyle(style)
            } else if (range.start < selection.min && range.end > selection.max) {
                // The style completely covers the selection. We need to split it.
                val oldEnd = range.end
                // Truncate the start part
                style.textRange = TextRange(range.start, selection.min)
                // Add a new style for the end part
                addStyle(
                    SpanStyle(fontWeight = FontWeight.Bold),
                    TextRange(selection.max, oldEnd),
                    ExpandPolicy.AtEnd,
                )
            } else if (range.start < selection.min) {
                // The style overlaps with the start of the selection. Truncate it.
                style.textRange = TextRange(range.start, selection.min)
            } else {
                // The style overlaps with the end of the selection. Truncate it.
                style.textRange = TextRange(selection.max, range.end)
            }
        }
    }
    fun TextFieldBuffer.boldSelection() {
        // Query existing bold styles in the selection
        val intersectingStyles =
            getSpanStyles(selection.min, selection.max).filter {
                it.spanStyle.fontWeight == FontWeight.Bold
            }
        // To keep bold styles non-overlapping, we merge any intersecting bold
        // styles with the new selection range into a single contiguous bold style.
        var mergedStart = selection.min
        var mergedEnd = selection.max
        for (style in intersectingStyles) {
            mergedStart = minOf(mergedStart, style.textRange.start)
            mergedEnd = maxOf(mergedEnd, style.textRange.end)
            // Remove the fragmented style
            removeStyle(style)
        }
        addStyle(
            SpanStyle(fontWeight = FontWeight.Bold),
            TextRange(mergedStart, mergedEnd),
            ExpandPolicy.AtEnd,
        )
    }
    Column {
        Button(
            onClick = {
                state.edit {
                    val selection = this.selection
                    if (selection.collapsed) return@edit
                    if (isSelection100PercentBold) {
                        unBoldSelection()
                    } else {
                        boldSelection()
                    }
                }
            }
        ) {
            Text(
                "B",
                fontWeight = if (isSelection100PercentBold) FontWeight.Bold else FontWeight.Normal,
            )
        }
        BasicTextField(state = state, textStyle = LocalTextStyle.current)
    }
}
```
