Skip to main content

Types of Props

The Components page details how to declare a component and its props as standard val properties. This page covers two more ways for a parent component to configure its children with props: Common props and Tree props.

Common Props​

note

A common prop is one of a set of properties that can be applied to any primitive component.

Common props are supported by all primitive components. They include View properties like onClick and background, visibility events like onVisible, as well as layout parameters like margin.

Common props are specified using the Style API, which enables one or more common props to be chained together into a Style object that is passed to the components as a prop, as shown in the following example:

val style = Style.margin(all = 4.px)
.backgroundColor(Color.RED)
.viewTag("my_view")

For a component to be configured with a Style, it should declare a Style prop (such as val style: Style? = null). It should then pass that Style object to one of the components it renders to, usually the root component it returns from render. In this way, the Style will eventually end up on a primitive component (for example, Text or Row). All common props end up being materialized by primitive components, as shown in the following example:

class StyledHelloComponent(private val name: String, private val style: Style? = null) :
KComponent() {

override fun ComponentScope.render(): Component {
return Text(style = style, text = "Hello $name!")
}
}

val componentWithOnClick =
StyledHelloComponent(name = "Common Props", style = Style.onClick { log("clicked!") })

Combining a Style from above with a local Style​

The following 'more advanced' example shows how you can combine a Style taken from above with the Style the component itself wants to define:

class OuterTextComponent : KComponent() {
override fun ComponentScope.render(): Component {
return InnerTextComponent(style = Style.margin(all = 8.dp))
}
}

class InnerTextComponent(private val style: Style? = null) : KComponent() {
override fun ComponentScope.render(): Component {
return Text(
style = Style.padding(all = 8.dp).alpha(.5f) + style,
text = "I accept style from a parent!")
}
}

Working with Style​

In the above example, you may have noticed the use of + to combine the Style passed from OuterTextComponent and the styles that InnerTextComponent defines. The + operator combines two Styles into a single Style without mutating either:

val alphaStyle = Style.alpha(1f)
val combinedStyle = alphaStyle + Style.padding(all = 8.dp).margin(all = 8.dp)

// Result:
// alphaStyle: (alpha: 1f)
// combinedStyle: (alpha: 1f) <- (padding-all: 8.dp) <- (margin-all: 8.dp)

Note that ordering around + matters: if a Style property is defined twice, the last definition takes precendence:

val alphaStyle = Style.alpha(1f)
val combinedStyle = alphaStyle + Style.padding(all = 8.dp).alpha(.5f)

// Result:
// combinedStyle will apply padding of 8.dp and alpha of .5f

Generally, Style objects are immutable: any time you combine styles or add new properties to a style, you get a new Style instance that contains all the properties of the previous style plus the new properties.

Java - Kotlin compatibility​

If you need to pass down a style from a Java class to a Kotlin component, use StyleCompat:

@LayoutSpec
class OuterStyleComponentSpec {

@OnCreateLayout
static Component onCreateLayout(ComponentContext c) {
return new InnerTextComponent(StyleCompat.marginDip(YogaEdge.ALL, 8).build());
}
}

For passing style from Kotlin code to a Java Spec component, you can use .kotlinStyle(), which is equivalent to setting all the common props the Style defines:

class OuterStyleKComponent : KComponent() {
override fun ComponentScope.render(): Component {
val style = Style.margin(all = 8.dp)
return OuterStyleComponent.create(context).kotlinStyle(style).build()
}
}

Tree Props​

note

A tree prop is a special type of prop that is transparently passed from a parent component to its children.

A TreeProp is a special type of prop which is transparently passed from a parent component to its children. It provides a convenient way to share contextual data or utilities in a tree without having to explicitly pass val properties to every component in your hierarchy.

Declaring a Tree Prop​

In order to declare a TreeProp you need to use TreePropProvider:

return TreePropProvider(
Typeface::class.java to Typeface.DEFAULT_BOLD,
String::class.java to getTextTitle(),
Int::class.java to Color.RED) {
TreePropsChildComponent()
}
note

You can only declare one TreeProp for any one given type. If a child of ParentComponent also defines a TreeProp of the given type, it will override the value of that TreeProp for all its children (but not for itself).

Using a Tree Prop​

The child component can access the TreeProp value through a ComponentScope.getTreeProp<>() method that has the same type that was declared in the parents TreePropProvider call:

val color = getTreeProp<Int>()
val typeface = getTreeProp<Typeface>()
val title = getTreeProp<String>()

When to Use Tree Props​

Tree Props are powerful, but if overused, they can make your component code more difficult to understand. The best practice is to only use tree props for properties that the whole tree needs to know about (such as theming information or loggers) and not just as a more convenient way to get props to the leaves of a tree of components.