or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composition-lifecycle.mdcomposition-local.mdeffects.mdindex.mdios-integration.mdsnapshot-system.mdstate-management.md

composition-local.mddocs/

0

# CompositionLocal

1

2

Context-like data flow mechanism for passing data implicitly down the composition tree without explicit parameter passing. CompositionLocal enables sharing data across the entire composition hierarchy while maintaining type safety.

3

4

## Capabilities

5

6

### CompositionLocal Creation

7

8

Functions for creating CompositionLocal instances with different update policies.

9

10

```kotlin { .api }

11

/**

12

* Creates a CompositionLocal that uses structural equality for change detection

13

* @param defaultFactory Optional factory for default value when no provider is found

14

* @return ProvidableCompositionLocal instance

15

*/

16

fun <T> compositionLocalOf(defaultFactory: (() -> T)? = null): ProvidableCompositionLocal<T>

17

18

/**

19

* Creates a CompositionLocal that uses referential equality for change detection

20

* Optimized for values that rarely change

21

* @param defaultFactory Optional factory for default value when no provider is found

22

* @return ProvidableCompositionLocal instance

23

*/

24

fun <T> staticCompositionLocalOf(defaultFactory: (() -> T)? = null): ProvidableCompositionLocal<T>

25

```

26

27

**Usage Examples:**

28

29

```kotlin

30

// Theme CompositionLocal

31

val LocalAppTheme = compositionLocalOf<AppTheme> {

32

error("No theme provided")

33

}

34

35

// User CompositionLocal with default

36

val LocalCurrentUser = compositionLocalOf { User.guest() }

37

38

// Static CompositionLocal for rarely-changing configuration

39

val LocalAppConfiguration = staticCompositionLocalOf {

40

AppConfiguration.default()

41

}

42

43

data class AppTheme(

44

val colors: ColorScheme,

45

val typography: Typography,

46

val spacing: Spacing

47

)

48

49

data class User(val id: String, val name: String) {

50

companion object {

51

fun guest() = User("guest", "Guest User")

52

}

53

}

54

```

55

56

### CompositionLocal Classes

57

58

Core classes and interfaces for the CompositionLocal system.

59

60

```kotlin { .api }

61

/**

62

* Base class for CompositionLocal providing read access

63

* @param T The type of value provided by this CompositionLocal

64

*/

65

abstract class CompositionLocal<T>(defaultFactory: (() -> T)?) {

66

/**

67

* Current value of this CompositionLocal in the composition

68

* Throws if no provider is found and no default factory was provided

69

*/

70

val current: T

71

@Composable get

72

73

/**

74

* Current value or null if no provider is found

75

*/

76

val currentOrNull: T?

77

@Composable get

78

}

79

80

/**

81

* CompositionLocal that can provide values to child compositions

82

*/

83

abstract class ProvidableCompositionLocal<T> : CompositionLocal<T> {

84

/**

85

* Creates a ProvidedValue for use with CompositionLocalProvider

86

* @param value The value to provide

87

* @return ProvidedValue instance

88

*/

89

infix fun provides(value: T): ProvidedValue<T>

90

91

/**

92

* Creates a ProvidedValue with a computed value

93

* @param value Function that computes the value

94

* @return ProvidedValue instance

95

*/

96

infix fun providesDefault(value: () -> T): ProvidedValue<T>

97

}

98

99

/**

100

* Represents a value provided to a CompositionLocal

101

*/

102

class ProvidedValue<T> internal constructor(

103

val compositionLocal: CompositionLocal<T>,

104

val value: T,

105

val canOverride: Boolean

106

)

107

```

108

109

### CompositionLocalProvider

110

111

Function for providing values to CompositionLocals.

112

113

```kotlin { .api }

114

/**

115

* Provides values to CompositionLocals for the content lambda

116

* @param values Variable number of ProvidedValue instances

117

* @param content Composable content that can access the provided values

118

*/

119

@Composable

120

fun CompositionLocalProvider(

121

vararg values: ProvidedValue<*>,

122

content: @Composable () -> Unit

123

): Unit

124

```

125

126

**Usage Examples:**

127

128

```kotlin

129

@Composable

130

fun App() {

131

val theme = remember { AppTheme.default() }

132

val user = remember { getCurrentUser() }

133

134

CompositionLocalProvider(

135

LocalAppTheme provides theme,

136

LocalCurrentUser provides user

137

) {

138

MainScreen() // Can access theme and user via CompositionLocal

139

}

140

}

141

142

@Composable

143

fun MainScreen() {

144

// Access provided values

145

val theme = LocalAppTheme.current

146

val user = LocalCurrentUser.current

147

148

Column(

149

modifier = Modifier.background(theme.colors.background)

150

) {

151

Text(

152

text = "Welcome, ${user.name}!",

153

style = theme.typography.headlineMedium,

154

color = theme.colors.onBackground

155

)

156

157

UserContent() // Can also access the same CompositionLocals

158

}

159

}

160

```

161

162

### Reading CompositionLocal Values

163

164

Methods for safely accessing CompositionLocal values.

165

166

```kotlin { .api }

167

/**

168

* Extension property to get current value (same as .current)

169

*/

170

val <T> CompositionLocal<T>.current: T

171

@Composable get

172

173

/**

174

* Extension property to get current value or null if not provided

175

*/

176

val <T> CompositionLocal<T>.currentOrNull: T?

177

@Composable get

178

```

179

180

**Usage Examples:**

181

182

```kotlin

183

@Composable

184

fun SafeCompositionLocalAccess() {

185

// Safe access with null check

186

val user = LocalCurrentUser.currentOrNull

187

188

if (user != null) {

189

Text("Hello, ${user.name}")

190

} else {

191

Text("Please log in")

192

}

193

194

// Direct access (throws if not provided and no default)

195

val theme = LocalAppTheme.current

196

197

// Using in conditional logic

198

val isGuest = LocalCurrentUser.currentOrNull?.id == "guest"

199

}

200

```

201

202

## Common CompositionLocal Patterns

203

204

### Nested Providers

205

206

```kotlin

207

@Composable

208

fun NestedProvidersExample() {

209

val lightTheme = AppTheme.light()

210

211

CompositionLocalProvider(LocalAppTheme provides lightTheme) {

212

Column {

213

Text("Light theme content")

214

215

// Override theme for specific section

216

val darkTheme = AppTheme.dark()

217

CompositionLocalProvider(LocalAppTheme provides darkTheme) {

218

Text("Dark theme content")

219

220

NestedContent() // Uses dark theme

221

}

222

223

Text("Back to light theme")

224

}

225

}

226

}

227

```

228

229

### Dynamic Value Updates

230

231

```kotlin

232

@Composable

233

fun DynamicCompositionLocalExample() {

234

var isDarkMode by remember { mutableStateOf(false) }

235

236

val theme = if (isDarkMode) AppTheme.dark() else AppTheme.light()

237

238

CompositionLocalProvider(LocalAppTheme provides theme) {

239

Column {

240

Switch(

241

checked = isDarkMode,

242

onCheckedChange = { isDarkMode = it }

243

)

244

245

ThemedContent() // Automatically updates when theme changes

246

}

247

}

248

}

249

```

250

251

### Custom CompositionLocal Scope

252

253

```kotlin

254

// Custom scope for feature-specific data

255

val LocalFeatureConfig = compositionLocalOf<FeatureConfig> {

256

FeatureConfig.default()

257

}

258

259

@Composable

260

fun FeatureScope(

261

config: FeatureConfig,

262

content: @Composable () -> Unit

263

) {

264

CompositionLocalProvider(LocalFeatureConfig provides config) {

265

content()

266

}

267

}

268

269

@Composable

270

fun FeatureScreen() {

271

FeatureScope(config = FeatureConfig.forUser(currentUser)) {

272

FeatureContent() // Can access LocalFeatureConfig

273

}

274

}

275

```

276

277

## iOS Platform Integration

278

279

### iOS-Specific CompositionLocals

280

281

```kotlin

282

// iOS-specific configuration

283

val LocalIOSConfiguration = compositionLocalOf<IOSConfiguration> {

284

error("iOS configuration not provided")

285

}

286

287

val LocalUIViewController = compositionLocalOf<UIViewController?> { null }

288

289

data class IOSConfiguration(

290

val statusBarStyle: UIStatusBarStyle,

291

val interfaceOrientation: UIInterfaceOrientation,

292

val safeAreaInsets: EdgeInsets

293

)

294

295

@Composable

296

fun IOSApp(viewController: UIViewController) {

297

val iosConfig = remember {

298

IOSConfiguration(

299

statusBarStyle = UIStatusBarStyle.default,

300

interfaceOrientation = UIInterfaceOrientation.portrait,

301

safeAreaInsets = viewController.view.safeAreaInsets.toEdgeInsets()

302

)

303

}

304

305

CompositionLocalProvider(

306

LocalUIViewController provides viewController,

307

LocalIOSConfiguration provides iosConfig

308

) {

309

AppContent()

310

}

311

}

312

```

313

314

### Integration with UIKit

315

316

```kotlin

317

@Composable

318

fun UIKitIntegrationExample() {

319

val viewController = LocalUIViewController.currentOrNull

320

val iosConfig = LocalIOSConfiguration.current

321

322

LaunchedEffect(iosConfig.statusBarStyle) {

323

viewController?.setNeedsStatusBarAppearanceUpdate()

324

}

325

326

// Use iOS configuration in Composable

327

Column(

328

modifier = Modifier.padding(iosConfig.safeAreaInsets)

329

) {

330

// Content respects safe area insets

331

}

332

}

333

```

334

335

## Advanced Patterns

336

337

### CompositionLocal Transformation

338

339

```kotlin

340

@Composable

341

fun TransformCompositionLocalExample() {

342

val baseTheme = LocalAppTheme.current

343

344

// Create derived theme

345

val dialogTheme = remember(baseTheme) {

346

baseTheme.copy(

347

colors = baseTheme.colors.copy(

348

surface = baseTheme.colors.surfaceVariant

349

)

350

)

351

}

352

353

CompositionLocalProvider(LocalAppTheme provides dialogTheme) {

354

DialogContent() // Uses modified theme

355

}

356

}

357

```

358

359

### Conditional Provision

360

361

```kotlin

362

@Composable

363

fun ConditionalProvisionExample(user: User?) {

364

if (user != null) {

365

CompositionLocalProvider(LocalCurrentUser provides user) {

366

AuthenticatedContent()

367

}

368

} else {

369

UnauthenticatedContent() // LocalCurrentUser not provided

370

}

371

}

372

```

373

374

### Multiple Providers with Same Local

375

376

```kotlin

377

@Composable

378

fun MultipleProvidersExample() {

379

val adminTheme = AppTheme.admin()

380

val userTheme = AppTheme.user()

381

382

Row {

383

CompositionLocalProvider(LocalAppTheme provides adminTheme) {

384

AdminPanel()

385

}

386

387

CompositionLocalProvider(LocalAppTheme provides userTheme) {

388

UserPanel()

389

}

390

}

391

}

392

```

393

394

## Performance Considerations

395

396

- **Static vs Dynamic**: Use `staticCompositionLocalOf` for rarely-changing values to optimize recomposition

397

- **Scope Minimization**: Provide CompositionLocal values as close as possible to where they're needed

398

- **Value Stability**: Ensure provided values are stable to avoid unnecessary recomposition

399

- **Default Factories**: Use default factories sparingly as they're called on every access when no provider exists

400

- **Nested Providers**: Minimize deep nesting of providers to reduce composition overhead