Skip to content

Commit 62b6a60

Browse files
committed
docs: add guide for creating a custom renderer
* Add a new documentation page (create-renderer.md) explaining how to implement a custom renderer for jsonforms-kotlin. * Describe the concept of a renderer and the use of scope interfaces (RendererStringScope, RendererNumberScope, RendererBooleanScope, RendererLayoutScope). * Provide step-by-step instructions and example code for building custom field and layout renderers. * Show how to integrate the custom renderer with the JsonForm component. * Update mkdocs.yml to include the new "Create Renderer" page in the documentation navigation. * Reference Material3 and Cupertino renderer source code for further inspiration. Closes #16
1 parent 89f0f46 commit 62b6a60

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

docs/create-renderer.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
This page explains how to create your own renderer for `jsonforms-kotlin`, allowing you to fully
2+
customize the look and feel of forms to match your internal design system or branding. This is
3+
useful if the provided renderers do not meet your requirements.
4+
5+
## What is a renderer?
6+
7+
A renderer is a set of composable functions that define how each form field and layout should be
8+
displayed. You implement these by providing composable extensions for the various scope interfaces:
9+
`RendererStringScope`, `RendererNumberScope`, `RendererBooleanScope`, and `RendererLayoutScope`.
10+
11+
## Steps to create a custom renderer
12+
13+
**Implement field renderers**: Create composable extension functions for each field type and use the scope API to access field metadata, options, and state.
14+
15+
* `RendererStringScope.YourStringProperty(...)`
16+
* `RendererNumberScope.YourNumberProperty(...)`
17+
* `RendererBooleanScope.YourBooleanProperty(...)`
18+
19+
**Implement layout renderer**: Create a composable extension for `RendererLayoutScope`
20+
(e.g., `YourLayout(...)`) to control how groups of fields are arranged (vertical, horizontal, etc).
21+
22+
**Use your Renderer in JsonForm**: Pass your custom composables to the `JsonForm` component's
23+
`layoutContent`, `stringContent`, `numberContent`, and `booleanContent` slots.
24+
25+
**Example: Minimal custom renderer**
26+
27+
```kotlin
28+
@Composable
29+
fun RendererStringScope.MyStringProperty(
30+
value: String?,
31+
error: String? = null,
32+
onValueChange: (String) -> Unit,
33+
) {
34+
// Use scope methods for label, enabled, etc.
35+
MyTextField(
36+
value = value ?: "",
37+
label = label(),
38+
enabled = enabled(),
39+
error = error,
40+
onValueChange = onValueChange
41+
)
42+
}
43+
44+
@Composable
45+
fun RendererNumberScope.MyNumberProperty(
46+
value: String?,
47+
error: String? = null,
48+
onValueChange: (String) -> Unit,
49+
) {
50+
MyNumberField(
51+
value = value ?: "",
52+
label = label(),
53+
enabled = enabled(),
54+
error = error,
55+
onValueChange = onValueChange
56+
)
57+
}
58+
59+
@Composable
60+
fun RendererBooleanScope.MyBooleanProperty(
61+
value: Boolean,
62+
onValueChange: (Boolean) -> Unit,
63+
) {
64+
MySwitch(
65+
checked = value,
66+
label = label(),
67+
enabled = enabled(),
68+
onCheckedChange = onValueChange
69+
)
70+
}
71+
72+
@Composable
73+
fun RendererLayoutScope.MyLayout(
74+
content: @Composable (UiSchema) -> Unit
75+
) {
76+
Column {
77+
elements().forEach { child ->
78+
content(child)
79+
}
80+
}
81+
}
82+
```
83+
84+
## Using your renderer
85+
86+
```kotlin
87+
JsonForm(
88+
schema = schema,
89+
uiSchema = uiSchema,
90+
state = state,
91+
layoutContent = { MyLayout(content = it) },
92+
stringContent = { scope ->
93+
MyStringProperty(
94+
value = state[scope.id].value as String?,
95+
error = state.error(scope.id).value,
96+
onValueChange = { state[scope.id] = it }
97+
)
98+
},
99+
numberContent = { scope ->
100+
MyNumberProperty(
101+
value = state[scope.id].value as String?,
102+
error = state.error(scope.id).value,
103+
onValueChange = { state[scope.id] = it }
104+
)
105+
},
106+
booleanContent = { scope ->
107+
MyBooleanProperty(
108+
value = state[scope.id].value as Boolean? ?: false,
109+
onValueChange = { state[scope.id] = it }
110+
)
111+
}
112+
)
113+
```
114+
115+
For more details, see the [API reference](api/index.html) and the source code of the
116+
[Material3](../renderers/material3/) and [Cupertino](../renderers/cupertino/) renderers for
117+
inspiration.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ nav:
1515
- "Usage": usage.md
1616
- "State Management": state-management.md
1717
- "Custom Rendering": custom-rendering.md
18+
- "Create Renderer": create-renderer.md
1819
- "API reference": api/index.html
1920

2021
theme:

0 commit comments

Comments
 (0)