The Android XR SDK is now available in Developer Preview. We want your feedback! Visit our
support page to reach out.
Add a subspace to your app
Stay organized with collections
Save and categorize content based on your preferences.
A subspace is a partition of 3D space within your app where you can place 3D
models, build 3D layouts, and add depth to otherwise 2D content. A subspace is
rendered only when spatialization is enabled. In Home Space or on non-XR
devices, any code within that subspace is ignored.
You can use subspace composables such as Volume
and SpatialPanel
for placing 3D models. Some XR components such as Orbiter
or
SpatialDialog
are standard 2D composables that can be used anywhere in
your 2D UI hierarchy, but SubspaceComposable
s must be invoked in your
app's subspace. To do this, use either the ApplicationSubspace
composable or
the Subspace
composable.
As the name suggests, the ApplicationSubspace
composable should contain
all of your app's spatialized content. The Subspace
composable is ideal
for nesting a partition of 3D space deeper in your app's existing UI hierarchy.
As with any other composable, you can call Subspace
directly in your 2D
UI hierarchy. However, it's important to be aware of the implications of where
in the hierarchy you invoke Subspace
.
About subspace hierarchies
The top-level subspace is the outermost subspace invoked by your app. Use the
ApplicationSubspace
composable for your top-level subspace, but, if you
only use the Subspace composable in your app, the outermost Subspace
composable will be your top-level subspace. By default, this top-level subspace
is bounded by the recommended space for viewing an app, and it's typically where
you place your app's spatial layout and SpatialPanel
. If you need to
change the bounds of the top-level subspace, pass different
VolumeConstraints
to your ApplicationSubspace
.
However, if you nest another subspace inside of a 2D UI hierarchy in a panel
that's contained in the top-level subspace, that nested subspace behaves
differently.
Nested subspaces have two key differences from top-level Subspace
:
- They participate in the 2D layout in which they are invoked. This means that
the height and width of the subspace will be constrained by the height and
width of its 2D parent layout.
- They behave as children of the entity they're invoked in. This means that,
if you call a
Subspace
composable nested inside of a
SpatialPanel
, that subspace is a child of the SpatialPanel
it's called in.
These behaviors of nested subspace enable capabilities such as:
- Moving the child with the parent entity
- Offsetting the location of the child using the offset
SubspaceModifier
- Presenting a 3D object that hovers above your 2D UI and matches the height
and width of the appropriate space in the 2D layout
Add a subspace to your app
The following code example shows how to add top-level and nested subspaces to
your app:
setContent {
// This is a top-level subspace
ApplicationSubspace {
SpatialPanel {
MyComposable()
}
}
}
@Composable
private fun MyComposable() {
Row {
PrimaryPane()
SecondaryPane()
}
}
@Composable
private fun PrimaryPane() {
// This is a nested subspace, because PrimaryPane is in a SpatialPanel
// and that SpatialPanel is in a top-level Subspace
Subspace {
ObjectInAVolume(true)
}
}
Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
Last updated 2025-07-31 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-07-31 UTC."],[],[],null,["# Add a subspace to your app\n\nA subspace is a partition of 3D space within your app where you can place 3D\nmodels, build 3D layouts, and add depth to otherwise 2D content. A subspace is\nrendered only when spatialization is enabled. In Home Space or on non-XR\ndevices, any code within that subspace is ignored.\n\nYou can use subspace composables such as [`Volume`](/reference/kotlin/androidx/xr/compose/subspace/package-summary#Volume(androidx.xr.compose.subspace.layout.SubspaceModifier,kotlin.Function1)) and [`SpatialPanel`](/reference/kotlin/androidx/xr/compose/subspace/package-summary#SpatialPanel(androidx.xr.compose.subspace.layout.SubspaceModifier,androidx.xr.compose.subspace.layout.SpatialShape,kotlin.Function0))\nfor placing 3D models. Some XR components such as [`Orbiter`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Orbiter(androidx.xr.compose.spatial.ContentEdge.Horizontal,androidx.compose.ui.unit.Dp,androidx.xr.compose.spatial.OrbiterOffsetType,androidx.compose.ui.Alignment.Horizontal,androidx.xr.compose.subspace.layout.SpatialShape,androidx.compose.ui.unit.Dp,kotlin.Boolean,kotlin.Function0)) or\n[`SpatialDialog`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#SpatialDialog(kotlin.Function0,androidx.xr.compose.spatial.SpatialDialogProperties,kotlin.Function0)) are standard 2D composables that can be used anywhere in\nyour 2D UI hierarchy, but [`SubspaceComposable`](/reference/kotlin/androidx/xr/compose/subspace/SubspaceComposable)s must be invoked in your\napp's subspace. To do this, use either the `ApplicationSubspace` composable or\nthe [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)) composable.\n\nAs the name suggests, the [`ApplicationSubspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#ApplicationSubspace(androidx.xr.compose.unit.VolumeConstraints,androidx.xr.compose.spatial.ConstraintsBehavior,kotlin.Function1)) composable should contain\nall of your app's spatialized content. The [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)) composable is ideal\nfor nesting a partition of 3D space deeper in your app's existing UI hierarchy.\n\nAs with any other composable, you can call [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)) directly in your 2D\nUI hierarchy. However, it's important to be aware of the implications of where\nin the hierarchy you invoke [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)).\n\nAbout subspace hierarchies\n--------------------------\n\nThe top-level subspace is the outermost subspace invoked by your app. Use the\n[`ApplicationSubspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#ApplicationSubspace(androidx.xr.compose.unit.VolumeConstraints,androidx.xr.compose.spatial.ConstraintsBehavior,kotlin.Function1)) composable for your top-level subspace, but, if you\nonly use the Subspace composable in your app, the outermost `Subspace`\ncomposable will be your top-level subspace. By default, this top-level subspace\nis bounded by the recommended space for viewing an app, and it's typically where\nyou place your app's spatial layout and [`SpatialPanel`](/reference/kotlin/androidx/xr/compose/subspace/package-summary#SpatialPanel(androidx.xr.compose.subspace.layout.SubspaceModifier,androidx.xr.compose.subspace.layout.SpatialShape,kotlin.Function0)). If you need to\nchange the bounds of the top-level subspace, pass different\n[`VolumeConstraints`](/reference/kotlin/androidx/xr/compose/unit/VolumeConstraints) to your [`ApplicationSubspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#ApplicationSubspace(androidx.xr.compose.unit.VolumeConstraints,androidx.xr.compose.spatial.ConstraintsBehavior,kotlin.Function1)).\n\nHowever, if you nest another subspace inside of a 2D UI hierarchy in a panel\nthat's contained in the top-level subspace, that nested subspace behaves\ndifferently.\n\nNested subspaces have two key differences from top-level [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)):\n\n- They participate in the 2D layout in which they are invoked. This means that the height and width of the subspace will be constrained by the height and width of its 2D parent layout.\n- They behave as children of the entity they're invoked in. This means that, if you call a [`Subspace`](/reference/kotlin/androidx/xr/compose/spatial/package-summary#Subspace(kotlin.Function1)) composable nested inside of a [`SpatialPanel`](/reference/kotlin/androidx/xr/compose/subspace/package-summary#SpatialPanel(androidx.xr.compose.subspace.layout.SubspaceModifier,androidx.xr.compose.subspace.layout.SpatialShape,kotlin.Function0)), that subspace is a child of the [`SpatialPanel`](/reference/kotlin/androidx/xr/compose/subspace/package-summary#SpatialPanel(androidx.xr.compose.subspace.layout.SubspaceModifier,androidx.xr.compose.subspace.layout.SpatialShape,kotlin.Function0)) it's called in.\n\nThese behaviors of nested subspace enable capabilities such as:\n\n- Moving the child with the parent entity\n- Offsetting the location of the child using the offset [`SubspaceModifier`](/reference/kotlin/androidx/xr/compose/subspace/layout/SubspaceModifier)\n- Presenting a 3D object that hovers above your 2D UI and matches the height and width of the appropriate space in the 2D layout\n\nAdd a subspace to your app\n--------------------------\n\nThe following code example shows how to add top-level and nested subspaces to\nyour app:\n\n\n```kotlin\nsetContent {\n // This is a top-level subspace\n ApplicationSubspace {\n SpatialPanel {\n MyComposable()\n }\n }\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/xr/src/main/java/com/example/xr/compose/Subspace.kt#L34-L41\n```\n\n\u003cbr /\u003e\n\n\n```kotlin\n@Composable\nprivate fun MyComposable() {\n Row {\n PrimaryPane()\n SecondaryPane()\n }\n}\n\n@Composable\nprivate fun PrimaryPane() {\n // This is a nested subspace, because PrimaryPane is in a SpatialPanel\n // and that SpatialPanel is in a top-level Subspace\n Subspace {\n ObjectInAVolume(true)\n }\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/xr/src/main/java/com/example/xr/compose/Subspace.kt#L47-L62\n```\n\n\u003cbr /\u003e"]]