Styling
Widgets all come with a default style. You will most certainly want to override those default styles to make your app look good.
In Fabulous, this is done by adding modifiers to your widgets. We will see in this page how to add those modifiers and how to reuse a style across your app.
Basic styling
Adding some basic style is easy. You simply need to apply modifiers on the widget you want to style by using the dot notation.
That’s it!
You can explore available modifiers on each widget by simply typing .
(dot) after the widget itself.
To be able to apply modifiers to widgets accepting multiple children (like VStack
), you will need to wrap the parent and its children in parenthesis like this (VStack() { child1 ... child2 }).modifier()
. Otherwise, F# won’t allow you to apply modifiers.
A suggestion to change the F# language is currently under review. Give it a thumb up if you’d like to see it in the future: F# Suggestion: Allow dot notation after body of computation expression without need for parenthesis
In case you want to see which modifiers are available for a certain widget, you can refer to the API documentation of that widget: API documentation
Applying a same style across multiple widgets
When building your app, you will probably want to apply the same style to multiple places. The bruteforce way is to simply repeat the same modifiers on each widget.
While it works, it has several drawbacks:
Lots of repeated code
Less readable
Less maintainable
You might want to refactor and extract that style to be able to reuse it across your app. Fortunately, Fabulous has you covered.
When you want to apply the same group of modifiers on each widgets of a same type, you can write your own shorthand modifier:
As you can see, the largeText
modifier will automatically apply the font size, the font family, the text alignment, the text color and the padding to all Label
widgets where it’s applied.
In addition to this shorthand modifier, you can still use all available modifiers on the same widget.
How to write a shorthand modifier
Writing a shorthand modifier can be overwhelming the first time. It is making use of several advanced features of F#. Let’s take a step back and decompose the code.
First thing to understand is that a shorthand modifier is actually implemented as an extension method.
To write an extension method, you need to have the following basic structure:
Let’s start by adding the keyword inline
before the name of the method. This will let Fabulous optimize the code for better performances at runtime.
Now, the most important part to understand: when using a widget, Fabulous will actually give you an instance of WidgetBuilder<'msg, 'marker>
where 'marker
will be a type representing the widget.
For example, Label()
will give you WidgetBuilder<'msg, IFabLabel>
,
You might have noticed that in the code above, we are using #IFabLabel
instead of IFabLabel
. This #
(pound) symbol is called a flexible type annotation.
It lets F# know that we actually want the shorthand modifier to be available to all widgets deriving from IFabLabel
, not just FabLabel
.
Another example that will make more sense is the backgroundColor
modifier of VisualElement
.
VisualElement
is a common ancestor to most widgets (Label
, Button
, Image
, etc.). They all can have a background color.
So, by using the flexible type annotation, Fabulous will make the backgroundColor
modifier available to all widgets that derive from IFabVisualElement
like Label
and Button
.
Adding this annotation depends on your needs. We recommend you add it by default. If you don’t add it, the shorthand modifier will only be available to the specific widget type you are targeting.
Now, let’s get back to our example. Based on all we just said, you should have the following code:
Here on the last line, this
is actually the widget you’re trying to modify. So, you have access to all its modifiers and can write the style you want to share.
Which gives us the example we saw at the beginning:
Reusing a widget and its style
There are 2 ways of reusing a widget and its style:
With a function
With a custom widget
They both have pros and cons, use the one that fits your needs.
With a function
Since in F# everything is function, you can reuse a widget by putting it in its own function.
Pros: Easy to write Cons: Don’t support optional parameters, not easily shared across multiple projects
With a custom widget
In case you want to share a widget with other projects (like in a NuGet packages), or if you want to optionally override some modifiers, you can use a custom widget.
It’s essentially the same than the function above, but you can have optional overrides by using the ?
(question mark) symbol before a parameter.
Also, custom widgets are more easily discoverable since they will be available at the same place with all other widgets, hence better for sharing with others.
It is generally better to annotate the module with [<AutoOpen>]
to automatically show the custom widget to everyone without first having to open the namespace.
It is strongly recommended to add the inline
keyword to allow Fabulous to optimize the code for better performances at runtime.
Pros: support optional parameters, easy to share across multiple projects Cons: harder to write
Reusing a complex hierarchy of widgets
Same as above, you can make use of the same 2 techniques to reuse a set of widgets.
Real world example
Here is an example coming from the Gallery app sample. We need to let the user switch between 2 views: the running samples and the samples' code.
It is essentially 2 radio buttons that are linked together. They share a custom style.
To do that, we created a radioButton
function that let us reuse a frame with a label to act as a single radio button.
Then, we created a custom widget SampleViewSelector
to be able to have several radio buttons together and know which one is selected.
Once done, we can use our custom widget in our view.
Legacy XAML styling
If any of the above techniques doesn’t work for you or if you’re trying to use an existing style written in C#/XAML, you can still use the legacy XAML styling.
Every widget has a style
modifier accepting a Xamarin.Forms.Style
instance.
You also have the option to set a resource dictionary on the Application widget with the resources
modifier.
For more information about styling in XAML, please read Styling Xamarin.Forms Apps using XAML Styles.
Please note that it is recommend to declare the XAML styles and resources outside of the view
function.
The view
function is executed on each update and therefore the styles and resources will be recreated each time, incurring a big memory cost since they are reference types.
Last updated