Understanding JSON Layout Structure
Compose Remote Layout uses a well-defined JSON structure to represent UI components. This guide provides a comprehensive reference for the JSON format and how it maps to Compose UI elements.
JSON Structure Overview
Every component in a Compose Remote Layout follows this basic pattern:
{
"componentType": {
"modifier": {
"base": {
// Base modifiers common to all components
}
// Component-specific modifiers
},
// Component-specific properties
"children": [
// Child components (for container components)
]
}
}
The root of any layout must be a single component, identified by the top-level key (like "column"
,
"row"
, etc.).
Component Types Reference
Compose Remote Layout supports the following built-in component types:
Container Components
These components can contain other components as children.
Column
Creates a vertical arrangement of children elements, similar to Compose's Column
.
{
"column": {
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"all": 16
}
},
"verticalArrangement": "spaceBetween",
"horizontalAlignment": "center"
},
"children": [
// Child components
]
}
}
Specific Modifiers:
verticalArrangement
: Controls spacing of children ("top"
,"center"
,"bottom"
,"spaceBetween"
,"spaceAround"
,"spaceEvenly"
)horizontalAlignment
: Aligns children horizontally ("start"
,"center"
,"end"
)
Row
Creates a horizontal arrangement of children elements, similar to Compose's Row
.
{
"row": {
"modifier": {
"base": {
"fillMaxWidth": true
},
"horizontalArrangement": "spaceBetween",
"verticalAlignment": "center"
},
"children": [
// Child components
]
}
}
Specific Modifiers:
horizontalArrangement
: Controls spacing of children ("start"
,"center"
,"end"
,"spaceBetween"
,"spaceAround"
,"spaceEvenly"
)verticalAlignment
: Aligns children vertically ("top"
,"center"
,"bottom"
)
Box
Overlays children on top of each other, similar to Compose's Box
.
{
"box": {
"modifier": {
"base": {
"size": 200
},
"contentAlignment": "center"
},
"children": [
// Child components - first child at the bottom, last child on top
]
}
}
Specific Modifiers:
contentAlignment
: Positions children within the box ("center"
,"topStart"
,"topCenter"
,"topEnd"
,"centerStart"
,"centerEnd"
,"bottomStart"
,"bottomCenter"
,"bottomEnd"
)
Grid
Arranges children in a grid pattern.
{
"grid": {
"modifier": {
"base": {
"fillMaxWidth": true,
"scrollable": true
},
"columns": 3,
"rows": 2,
"orientation": "vertical",
"horizontalArrangement": "spaceBetween",
"verticalArrangement": "center",
"enableSnapHorizontal": false
},
"children": [
// Child components
]
}
}
Specific Modifiers:
columns
: Number of columns (for vertical orientation)rows
: Number of rows (for horizontal orientation)orientation
: Direction of the grid ("vertical"
or"horizontal"
)horizontalArrangement
: Controls horizontal spacingverticalArrangement
: Controls vertical spacingenableSnapHorizontal
: Enables snap scrolling for horizontal grids
Card
Creates a Material Design card that can contain children.
{
"card": {
"modifier": {
"base": {
"padding": {
"all": 16
}
}
},
"children": [
// Child components
]
}
}
Content Components
These components typically display content rather than containing other components.
Text
Displays text content with various styling options.
{
"text": {
"content": "Hello World",
"fontSize": 16,
"fontWeight": "bold",
"color": "#0066CC",
"textAlign": "center",
"fontStyle": "normal",
"letterSpacing": 0,
"lineHeight": 20,
"maxLines": 2,
"minLines": 1,
"overflow": "ellipsis",
"textDecoration": "underline"
}
}
Properties:
content
: The text to display (supports bind values with{key}
syntax)fontSize
: Font size in spfontWeight
: Font weight ("thin"
,"extralight"
,"light"
,"normal"
,"medium"
,"semibold"
,"bold"
,"extrabold"
,"black"
, or numeric weights like"w100"
through"w900"
)color
: Text color as a hex stringtextAlign
: Text alignment ("start"
,"center"
,"end"
,"justify"
)fontStyle
: Font style ("normal"
,"italic"
)letterSpacing
: Additional space between letters in splineHeight
: Line height in spmaxLines
: Maximum number of lines before truncationminLines
: Minimum number of lines (adds space if content is shorter)overflow
: How to handle text overflow ("clip"
,"ellipsis"
,"visible"
)textDecoration
: Text decoration ("none"
,"underline"
,"linethrough"
,"underline linethrough"
)
Button
Creates an interactive button element.
{
"button": {
"content": "Click Me",
"clickId": "primary_button",
"fontSize": 14,
"fontWeight": "medium",
"fontColor": "#FFFFFF"
}
}
Properties:
content
: The button text (supports bind values)clickId
: Identifier for click handlingfontSize
,fontWeight
,fontColor
: Text styling propertiesletterSpacing
,lineHeight
,textAlign
,textDecoration
,maxLines
,minLines
,overflow
: Additional text styling properties
Buttons can also contain complex content using children
instead of content
:
{
"button": {
"clickId": "complex_button",
"children": [
{
"row": {
"children": [
{
"text": {
"content": "Submit"
}
}
]
}
}
]
}
}
Spacer
Creates empty space with specified dimensions.
Properties:
height
: Vertical space in dpwidth
: Horizontal space in dp
Custom Components
You can also use custom components that you've registered with CustomNodes
:
{
"profile_card": {
"username": "John Doe",
"avatar_url": "https://example.com/avatar.jpg",
"modifier": {
"base": {
"fillMaxWidth": true
}
},
"children": [
// Optional children depending on your custom component implementation
]
}
}
The properties available for custom components depend on your implementation.
Modifier System
The modifier system allows you to customize appearance and behavior of components.
Base Modifiers
These modifiers are common to all components:
Size Modifiers
"base": {
"width": 200, // Fixed width in dp
"height": 100, // Fixed height in dp
"size": 150, // Both width and height set to the same value
"fillMaxWidth": true, // Fill available width (equivalent to Modifier.fillMaxWidth())
"fillMaxHeight": false, // Fill available height
"fillMaxSize": false, // Fill available width and height
"wrapContentWidth": true, // Size to fit content horizontally
"wrapContentHeight": true, // Size to fit content vertically
"aspectRatio": 1.5 // Maintain this width to height ratio
}
Padding and Margin
"padding": {
"all": 16, // Apply 16dp padding on all sides
"horizontal": 16, // Left and right padding
"vertical": 8, // Top and bottom padding
"start": 16, // Start (left in LTR) padding
"top": 8, // Top padding
"end": 16, // End (right in LTR) padding
"bottom": 8 // Bottom padding
},
"margin": {
// Same properties as padding
"all": 8,
"horizontal": 8,
"vertical": 4,
"start": 8,
"top": 4,
"end": 8,
"bottom": 4
}
Background and Styling
"background": {
"color": "#FF0000", // Background color as hex
"alpha": 0.8, // Opacity (0.0 - 1.0)
"shape": "roundedcorner", // Shape type ("rectangle", "roundedcorner", "circle")
"radius": 8 // Corner radius for rounded corners
},
"border": {
"width": 2, // Border width in dp
"color": "#000000", // Border color as hex
"shape": {
"type": "roundedcorner",
"cornerRadius": 8, // Even corner radius
"topStart": 8, // Individual corner radii
"topEnd": 8,
"bottomStart": 8,
"bottomEnd": 8
}
},
"shadow": {
"elevation": 4, // Shadow elevation in dp
"shape": {
"type": "roundedcorner",
"cornerRadius": 8
}
}
Scrolling
Interaction
Transformations
"alpha": 0.9, // Component opacity (0.0 - 1.0)
"rotate": 45, // Rotation in degrees
"scale": {
"scaleX": 1.2, // Horizontal scale factor
"scaleY": 0.8 // Vertical scale factor
},
"offset": {
"x": 10, // Horizontal offset in dp
"y": 5 // Vertical offset in dp
},
"clip": true // Clip content to component bounds
Complete Examples
Simple Profile Card
Here's an example of a simple profile card:
{
"card": {
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"all": 16
},
"clickId": "view_profile"
}
},
"children": [
{
"row": {
"modifier": {
"verticalAlignment": "center"
},
"children": [
{
"box": {
"modifier": {
"base": {
"size": 64,
"background": {
"color": "#EEEEEE",
"shape": "circle"
}
},
"contentAlignment": "center"
},
"children": [
{
"text": {
"content": "{initials}",
"fontSize": 24,
"fontWeight": "bold",
"color": "#666666"
}
}
]
}
},
{
"spacer": {
"width": 16,
"height": 0
}
},
{
"column": {
"children": [
{
"text": {
"content": "{username}",
"fontSize": 18,
"fontWeight": "bold"
}
},
{
"text": {
"content": "{email}",
"fontSize": 14,
"color": "#666666"
}
}
]
}
}
]
}
}
]
}
}
Interactive Counter
{
"column": {
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"all": 24
}
},
"horizontalAlignment": "center",
"verticalArrangement": "spaceBetween"
},
"children": [
{
"text": {
"content": "Counter",
"fontSize": 24,
"fontWeight": "bold"
}
},
{
"box": {
"modifier": {
"base": {
"padding": {
"vertical": 32
}
},
"contentAlignment": "center"
},
"children": [
{
"text": {
"content": "{count}",
"fontSize": 64,
"fontWeight": "bold",
"color": "{countColor}"
}
}
]
}
},
{
"row": {
"modifier": {
"base": {
"fillMaxWidth": true
},
"horizontalArrangement": "spaceEvenly"
},
"children": [
{
"button": {
"content": "-",
"clickId": "decrement",
"fontSize": 20
}
},
{
"button": {
"content": "+",
"clickId": "increment",
"fontSize": 20
}
}
]
}
},
{
"button": {
"content": "Reset",
"clickId": "reset",
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"vertical": 8
}
}
}
}
}
]
}
}
Scrollable Grid Layout
{
"column": {
"modifier": {
"base": {
"fillMaxWidth": true,
"padding": {
"all": 16
}
}
},
"children": [
{
"text": {
"content": "Product Categories",
"fontSize": 24,
"fontWeight": "bold"
}
},
{
"spacer": {
"height": 16
}
},
{
"grid": {
"modifier": {
"base": {
"fillMaxWidth": true,
"scrollable": true,
"height": 120
},
"orientation": "horizontal",
"rows": 1,
"enableSnapHorizontal": true,
"horizontalArrangement": "spaceBetween"
},
"children": [
{
"card": {
"modifier": {
"base": {
"width": 180,
"height": 100,
"clickId": "category:electronics"
}
},
"children": [
{
"box": {
"modifier": {
"contentAlignment": "center"
},
"children": [
{
"text": {
"content": "Electronics",
"fontSize": 18,
"fontWeight": "medium"
}
}
]
}
}
]
}
},
{
"card": {
"modifier": {
"base": {
"width": 180,
"height": 100,
"clickId": "category:clothing"
}
},
"children": [
{
"box": {
"modifier": {
"contentAlignment": "center"
},
"children": [
{
"text": {
"content": "Clothing",
"fontSize": 18,
"fontWeight": "medium"
}
}
]
}
}
]
}
},
{
"card": {
"modifier": {
"base": {
"width": 180,
"height": 100,
"clickId": "category:home"
}
},
"children": [
{
"box": {
"modifier": {
"contentAlignment": "center"
},
"children": [
{
"text": {
"content": "Home",
"fontSize": 18,
"fontWeight": "medium"
}
}
]
}
}
]
}
}
]
}
}
]
}
}
Best Practices
1. Keep Layout JSON Clean and Readable
- Use consistent indentation
- Group related components together
- Add comments in your code when generating JSON
- Consider using a JSON formatter for better readability
2. Start Simple and Build Up Complexity
- Begin with simple layouts
- Test each component individually
- Gradually combine components into more complex layouts
- Validate layout rendering at each step
3. Reuse Common Structures
- Identify repeating patterns
- Extract common layouts into reusable functions
- Use template systems if generating JSON dynamically
4. Consider Performance
- Avoid deeply nested structures when possible
- Be mindful of the number of components in scrollable containers
- Use lazy loading patterns for large lists (custom components with LazyColumn)
5. Test on Multiple Devices
- Verify layouts on different screen sizes
- Ensure your responsive design works as expected
- Check behavior with different font sizes (accessibility)
Troubleshooting Common Issues
Problem: Component Not Displaying
Possible causes:
- Invalid JSON structure
- Missing required properties
- Nested structure too complex
Solutions:
- Validate JSON with a JSON validator
- Start with a simpler version and add complexity gradually
- Check for typos in component type names
Problem: Layout Not Responding to Clicks
Possible causes:
- Missing
clickId
property - Incorrect handler implementation
Solutions:
- Ensure buttons have the
clickId
property set - For non-button components, add
clickId
to the base modifier - Verify click handler function is implemented correctly
Problem: Unexpected Layout Appearance
Possible causes:
- Conflicting modifiers
- Incorrect nesting of components
- Misunderstanding of component behavior
Solutions:
- Test individual components separately
- Review the documentation for specific components
- Use simpler alternatives if a component behaves unexpectedly
Next Steps
Now that you understand the JSON structure for layouts, you can:
- Try the Live Editor JSON for build and create your dynamic content