suiss/uim · React Native Component
Label
A text label for a form control that can be pressed to act on the control.
Label is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.


import { Label } from "@/components/ui/label"
export function LabelExample() {
return (
<Label>Your email address</Label>
)
}import EsuissUI
import SwiftUI
struct LabelExample: View {
var body: some View {
FieldLabel("Your email address")
}
}import androidx.compose.runtime.Composable
import com.esuiss.ui.components.Label
@Composable
fun LabelExample() {
Label("Your email address")
}Label renders a Text inside a Pressable row. The pressable accepts onPress, onLongPress, onPressIn and onPressOut, so pressing the label can toggle or focus the control next to it. A disabled label uses a muted color.
Installation
$ pnpm dlx @esuiss/uim@latest add label$ pnpm dlx @esuiss/uim@latest add label --platform swift$ pnpm dlx @esuiss/uim@latest add label --platform kotlinManual
- Install the dependencies:
npx expo install cn-
Add the pieces it builds on: the primitives
components/primitives/label.tsx,components/primitives/use-render.tsx. -
Copy the source into
components/ui/label.tsx:
import { cn } from "cn"
import * as LabelPrimitive from "@/components/primitives/label"
import { resolveClassName } from "@/components/primitives/use-render"
function Label({
className,
onPress,
onLongPress,
onPressIn,
onPressOut,
disabled,
...props
}: React.ComponentProps<typeof LabelPrimitive.Text>) {
return (
<LabelPrimitive.Root
className="flex-row items-center gap-2"- Update the import paths to match your project.
- Install the dependencies:
npx expo install cn-
Add the pieces it builds on: the primitives
components/primitives/label.tsx,components/primitives/use-render.tsx. -
Copy the source into
components/ui/label.tsx:
import { cn } from "cn"
import * as LabelPrimitive from "@/components/primitives/label"
import { resolveClassName } from "@/components/primitives/use-render"
function Label({
className,
onPress,
onLongPress,
onPressIn,
onPressOut,
disabled,
...props
}: React.ComponentProps<typeof LabelPrimitive.Text>) {
return (
<LabelPrimitive.Root
className="flex-row items-center gap-2"- Update the import paths to match your project.
-
Add the pieces it builds on: the primitives
components/primitives/label.tsx,components/primitives/use-render.tsx. -
Copy the source into
components/ui/label.tsx:
import { StyleSheet } from "react-native"
import * as LabelPrimitive from "@/components/primitives/label"
import { fontSize, useTheme } from "@/components/ui/theme"
const styles = StyleSheet.create({
root: {
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: 8,
},
text: { ...fontSize.base, fontWeight: "600" },
})
function Label({
style,- Update the import paths to match your project.
-
Target iOS 17 or later.
-
Copy the theme files every view uses:
import SwiftUI
import UIKit
struct RGBA: Sendable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
let alpha: CGFloat
init(_ hex: UInt32, _ alpha: CGFloat = 1) {
red = CGFloat((hex >> 16) & 0xFF) / 255
green = CGFloat((hex >> 8) & 0xFF) / 255
blue = CGFloat(hex & 0xFF) / 255
self.alpha = alpha
}import SwiftUI
extension Color {
public static let surface = Color.adaptive(light: .init(0xFFFFFF), dark: .init(0x000000))
public static let surfaceSecondary = Color.adaptive(light: .init(0xF5F5F7), dark: .init(0x161617))
public static let surfaceTertiary = Color.adaptive(light: .init(0xE8E8ED), dark: .init(0x2C2C2E))
public static let surfaceRaised = Color.adaptive(light: .init(0xFFFFFF), dark: .init(0x1D1D1F))
public static let label = Color.adaptive(light: .init(0x1D1D1F), dark: .init(0xF5F5F7))
public static let labelSecondary = Color.adaptive(light: .init(0x6E6E73), dark: .init(0xA1A1A6))
public static let labelTertiary = Color.adaptive(light: .init(0x86868B), dark: .init(0x86868B))
public static let labelQuaternary = Color.adaptive(light: .init(0xD2D2D7), dark: .init(0x424245))
public static let control = Color.adaptive(light: .init(0x000000, 0.04), dark: .init(0xFFFFFF, 0.1))
public static let controlPressed = Color.adaptive(light: .init(0x000000, 0.12), dark: .init(0xFFFFFF, 0.22))
public static let controlSelected = Color.adaptive(light: .init(0x1D1D1F), dark: .init(0xF5F5F7))
public static let controlDisabled = Color.adaptive(light: .init(0x000000, 0.03), dark: .init(0xFFFFFF, 0.05))
public static let onControlSelected = Color.adaptive(light: .init(0xFFFFFF), dark: .init(0x000000))- Copy the source and every file it uses:
import SwiftUI
public struct FieldLabel<Content: View>: View {
let content: Content
@Environment(\.fieldInset) private var inset
@Environment(\.isEnabled) private var isEnabled
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
public var body: some View {
content
.scaledTextStyle(.base, weight: inset ? .regular : .semibold)
.foregroundStyle(isEnabled ? Color.label : .labelQuaternary)import SwiftUI
extension EnvironmentValues {
@Entry public var isInvalid = false
@Entry var fieldInset = false
@Entry var fieldGroupInset = false
@Entry var fieldSetInset = false
}
extension View {
public func invalid(_ isInvalid: Bool = true) -> some View {
environment(\.isInvalid, isInvalid)
}
}
public enum FieldOrientation: CaseIterable, Sendable {import SwiftUI
public struct Separator: View {
let orientation: Axis
public init(_ orientation: Axis = .horizontal) {
self.orientation = orientation
}
public var body: some View {
Rectangle()
.fill(Color.separator)
.frame(width: orientation == .vertical ? 1 : nil, height: orientation == .horizontal ? 1 : nil)
.frame(maxWidth: orientation == .horizontal ? .infinity : nil, maxHeight: orientation == .vertical ? .infinity : nil)
.accessibilityHidden(true)
}import SwiftUI
public enum TextVariant: CaseIterable, Sendable {
case `default`, h1, h2, h3, h4, p, blockquote, code, lead, large, small, muted
var style: TextStyle {
switch self {
case .h1: .xl3
case .h2: .xl2
case .h3: .xl
case .h4, .lead, .large: .lg
case .code, .small, .muted: .sm
default: .base
}
}- Add the files to your app target.
- Set
minSdkto 24 or higher and add the dependencies:
implementation(platform("androidx.compose:compose-bom:2026.09.00"))
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.ui:ui")- Copy the theme files every view uses:
package com.esuiss.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.dropShadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.shadow.Shadow as DropShadow
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffsetpackage com.esuiss.ui.theme
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Immutable
data class Colors(
val surface: Color,
val surfaceSecondary: Color,
val surfaceTertiary: Color,
val surfaceRaised: Color,
val label: Color,
val labelSecondary: Color,
val labelTertiary: Color,
val labelQuaternary: Color,- Copy the source and every file it uses:
package com.esuiss.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.esuiss.ui.theme.EsuissTheme
import com.esuiss.ui.theme.Typography
@Composablepackage com.esuiss.ui.components
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
val LocalContentStyle = compositionLocalOf { TextStyle.Default }
val LocalContentColor = compositionLocalOf { Color.Unspecified }
val LocalIconSize = compositionLocalOf { 20.dp }- Update the
com.esuiss.uipackage names to match your project.
Usage
import { Label } from "@/components/ui/label"<Label>Your email address</Label>Set a nativeID on the label and point the control's accessibilityLabelledBy at it, so screen readers read the label with the control.
For a checkbox or switch, pass an onPress that toggles the control, which gives a larger touch target. Inside a Field, use FieldLabel instead.
Examples
With input
A label linked to an input through nativeID and accessibilityLabelledBy.


import { View } from "react-native"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
export function LabelWithInputExample() {
return (
<View className="gap-2">
<Label nativeID="label-email">Email</Label>
<Input
accessibilityLabelledBy="label-email"
placeholder="[email protected]"
/>
</View>
)
}import EsuissUI
import SwiftUI
struct LabelWithInput: View {
@State private var email = ""
var body: some View {
VStack(alignment: .leading, spacing: 8) {
FieldLabel("Email")
.accessibilityHidden(true)
TextField(String("[email protected]"), text: $email)
.textFieldStyle(.input)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
.accessibilityLabel(Text("Email"))
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Input
import com.esuiss.ui.components.Label
@Composable
fun LabelWithInput() {
var email by rememberSaveable { mutableStateOf("") }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Label("Email")
Input(email, { email = it }, Modifier.semantics { contentDescription = "Email" }, placeholder = "[email protected]")
}
}With checkbox
A label next to a checkbox that toggles it when pressed.


import * as React from "react"
import { View } from "react-native"
import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
function WithCheckboxDemo() {
const [checked, setChecked] = React.useState(false)
return (
<View className="flex-row items-center gap-3">
<Checkbox
accessibilityLabelledBy="label-terms"
checked={checked}
onCheckedChange={setChecked}
/>
<Label nativeID="label-terms" onPress={() => setChecked((v) => !v)}>
Accept terms and conditions
</Label>
</View>
)
}
export function LabelWithCheckboxExample() {
return (
<WithCheckboxDemo />
)
}import EsuissUI
import SwiftUI
struct LabelWithCheckbox: View {
@State private var checked = false
var body: some View {
Toggle(isOn: $checked) {
FieldLabel("Accept terms and conditions")
}
.toggleStyle(.checkbox)
}
}import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Checkbox
import com.esuiss.ui.components.Label
@Composable
fun LabelWithCheckbox() {
var checked by rememberSaveable { mutableStateOf(false) }
Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked, { checked = it }, Modifier.semantics { contentDescription = "Accept terms and conditions" })
Label(
"Accept terms and conditions",
Modifier.clickable(interactionSource = remember { MutableInteractionSource() }, indication = null) { checked = !checked },
)
}
}Disabled
A disabled label.


import { Label } from "@/components/ui/label"
export function LabelDisabledExample() {
return (
<Label disabled>Disabled label</Label>
)
}import EsuissUI
import SwiftUI
struct LabelDisabledExample: View {
var body: some View {
FieldLabel("Disabled label")
.disabled(true)
}
}import androidx.compose.runtime.Composable
import com.esuiss.ui.components.Label
@Composable
fun LabelDisabledExample() {
Label("Disabled label", enabled = false)
}API Reference
Label
React.ComponentProps<typeof LabelPrimitive.Text>Accessibility
- The label text reports its
disabledstate inaccessibilityState. - Link it to its control with
nativeIDon the label andaccessibilityLabelledByon the control.
Notes
- Text uses the
text-labeltoken, andtext-label-quaternarywhen disabled. - Light and dark colors follow the system appearance.