Want to try fastn for your company's website?
Book a Demo

`component`

A `component` in `ftd` is similar to "react component". Components are independent and reusable bits of code. `component`s have "arguments", these are the data that must be passed to them, and using `component`s we construct the user interface.

Create Your First Component

New components are defined using the `component` keyword followed by component name:
Creating a component named `heading`
-- component heading:

-- ftd.text: My Heading
color: red

-- end: heading
Lang:
ftd
Here, we have defined a new component `heading`. This component is using [`ftd.text`](ftd/text/), a kernel component, as a definition. We have created a custom-component which shows given text in `red` color.

Kernel Components

So, how is `ftd.text` implemented? `ftd` comes with some "kernel components", these are the lowest level components that every other component uses directly or indirectly. Read about our [kernel components guide](ftd/kernel/) to learn about these components.

Rendering a Component

Till now, we have created a component called `heading`. Now to invoke or render this component in your `ftd` application, we can do the following:
Input
-- heading:
Lang:
ftd
Output
My Heading
Currently, `My Heading` is fixed text displayed by `heading` component. We can make it customisable by using attributes.

Rendering a Component Conditionally

We can render a component conditionally. This can be achieved using an `if` keyword.
Input
-- integer num: 10

-- heading:
if: { num <= 10 }
Lang:
ftd
Output
My Heading
Input
-- integer num: 10

-- heading:
if: { num > 10 }

-- ftd.text: Heading not shown!!
Lang:
ftd
Output
Heading not shown!!

Component Arguments

Component "arguments" refer to the inputs that are passed into a component when it is called or invoked. These arguments provide the component with the necessary data that is helpful to configure or customize the component's behavior or appearance. Component arguments are like function arguments, and you send them into the component as attributes. The arguments in `ftd` components creates variables for each component invocation. These variables have local scope. This means that these variables can be accessed only inside the component definition in which they are declared.

Defining Component Arguments

Component arguments starts with argument type follow by argument name, in our component we can define one such argument, `title`. The type of our `title` argument is [`string`](ftd/built-in-types/#string).
Using the `title` argument in the component
-- component heading:
string title:

-- ftd.text: $heading.title
color: red

-- end: heading
Lang:
ftd

Adding Attributes to Component

When the component is used in another component or in the main application, the `title` can be passed in as an attribute of the component:
Input
-- heading:
title: I love `ftd`!
Lang:
ftd
Output
I love `ftd`!

Using Specially Typed Arguments

We can use special types like [`caption`](ftd/built-in-types/#caption), [`body`](ftd/built-in-types/#body) or [`caption or body`](ftd/built-in-types/#caption-or-body) that give us flexibility to pass attributes in different location of [`ftd::p1` "section"](ftd/p1-grammar/#section-caption). Let's use `caption or body` type using which we can pass attributes in either `caption` or `body` area.
`caption or body` type for `title` argument
-- component heading:
caption or body title:

-- ftd.text: $heading.title
color: red

-- end: heading
Lang:
ftd

Passing Attribute in Caption

Passing attribute in caption area makes the component more concise and readable. It also make it clear what the component represents and what its purpose is.
Input
-- heading: I am in caption area.
Lang:
ftd
Output
I am in caption area.

Passing Attribute in Body

Passing attributes in the body area can help make it more readable by providing a way to break up complex or lengthy inputs into more manageable chunks of text.
Input
-- heading:

I am in body area.

Since I am long description, it's better to pass it here. Isn't it?
Lang:
ftd
Output
I am in body area. Since I am long description, it's better to pass it here. Isn't it?
ℹ️
Special types
By default `caption` or `body` is alias for `string` but if you want to pass types other than `string` you can do the following:
Input
-- component show-number:
caption integer number:

-- ftd.integer: $show-number.number

-- end: show-number

-- show-number: 45
Lang:
ftd
Output
45

Arguments with Default Values

An argument can be defined with a default value:
-- component heading:
caption or body title:
ftd.color text-color: red

-- ftd.text: $heading.title
color: $heading.text-color

-- end: heading
Lang:
ftd
If no argument is provided, the component instance adopts the default value of `text-color` defined by the `heading`. On the other hand, if an argument is provided, it supersedes the default value.
`heading` with default `text-color`
Input
--  heading: hello
Lang:
ftd
Output
hello
`heading` with `text-color` value as `green`
Input
-- heading: this is nice
text-color: green
Lang:
ftd
Output
this is nice

Global Variable Reference As Default Value

We can pass global variable reference as a default value:
Passing global variable reference `ftd-title`
-- string ftd-title: I love `ftd`!

-- component heading:
caption or body title: $ftd-title
ftd.color text-color: red

-- ftd.text: $heading.title
color: $heading.text-color

-- end: heading
Lang:
ftd
Input
-- heading:
Lang:
ftd
Output
I love `ftd`!

Other Argument Reference As Default Value

We can pass other argument reference as a default value:
-- component heading-with-detail:
caption title:
body detail: $heading-with-detail.title

-- ftd.column:
spacing.fixed.px: 20
color: $inherited.colors.text

-- ftd.text: $heading-with-detail.title
role: $inherited.types.heading-small

-- ftd.text: $heading-with-detail.detail
role: $inherited.types.label-small

-- end: ftd.column

-- end: heading-with-detail
Lang:
ftd
Input
-- heading-with-detail: Title same as detail
Lang:
ftd
Output
Title same as detail
Title same as detail

Conditional Attributes

Sometimes we want to set an attribute based on a condition.
True Condition Expression
Input
-- integer num: 10

-- heading:
title if { num <= 10 }: `num` is less than equal to 10
title: Default Title
Lang:
ftd
Output
`num` is less than equal to 10
False Condition Expression
Input
-- heading:
title if { num > 10 }: `num` is less than equal to 10
title: Default Title
Lang:
ftd
Output
Default Title

Creating Container Component

`ftd` provides some container type kernel component like [`ftd.row`](ftd/row/) and [`ftd.column`](ftd/column/). The container component accepts the components as an attribute.

Using `ftd.ui list` type

We can define such arguments using [`ftd.ui list`](ftd/built-in-types/#ftd-ui) type.
-- component show-ui:
caption title:
ftd.ui list uis:

-- ftd.column:
spacing.fixed.px: 10
color: $inherited.colors.text

-- ftd.text: $show-ui.title

-- ftd.column:
children: $show-ui.uis
border-width.px: 1
padding.px: 10
border-color: $inherited.colors.border

-- end: ftd.column

-- end: ftd.column

-- end: show-ui
Lang:
ftd
Here, we have defined an argument `uis` of type `ftd.ui list`. We have also pass this to [`children`](ftd/container/#children) attribute of `ftd.column`.
Input
-- show-ui: My UIs

-- show-ui.uis:

-- ftd.text: My First UI
-- heading: Using Heading Too

-- end: show-ui.uis
Lang:
ftd
Output
My UIs
My First UI
Using Heading Too

Using `children` type

The [`children`](ftd/built-in-types/#children) type allows us to pass components in subsection location.
-- component show-ui:
caption title:
children uis:

-- ftd.column:
spacing.fixed.px: 10
color: $inherited.colors.text

-- ftd.text: $show-ui.title

-- ftd.column:
children: $show-ui.uis
border-width.px: 1
padding.px: 10
border-color: $inherited.colors.border

-- end: ftd.column

-- end: ftd.column

-- end: show-ui
Lang:
ftd
Input
-- show-ui: My UIs

-- ftd.text: My First UI
-- heading: Using Heading Too

-- end: show-ui
Lang:
ftd
Output
My UIs
My First UI
Using Heading Too

Mutable Component Arguments

In `ftd`, we can define a component argument as mutable by using the `$` prefix before its name. A mutable argument can be modified within the component and can take mutable variables as input, which can be modified outside the component's scope too. Any changes made to a mutable argument will be reflected in the component's output. Consider the following code snippet:
-- component toggle-ui:
caption title:
body description:
boolean $open: true

-- ftd.column:

-- ftd.text: $toggle-ui.title

-- ftd.text: $toggle-ui.description
if: { toggle-ui.open }

-- end: ftd.column

-- end: toggle-ui
Lang:
ftd
In the above example, the `$open` argument is mutable, which means it can be modified both within and outside the `toggle-ui` component. Any changes made to the `$open` argument will be immediately reflected in the component's output.
Input
-- toggle-ui: My Title
$open: false

My Description
Lang:
ftd
Output
My Title
Input
-- toggle-ui: My Title

My Description
Lang:
ftd
Output
My Title
My Description

Passing Mutable Variable to Mutable Argument

Consider the following code snippet:
-- boolean $global-open: true

-- ftd.text: I change global-open
$on-click$: $ftd.toggle($a = $global-open)

-- toggle-ui: My Title
$open: $global-open

My Description
Lang:
ftd
We have added an `$on-click$` [event](ftd/event/) here and used `ftd` built-in function `ftd.toggle`. The function toggles the boolean value whenever event occurs. We have passed mutable reference of `global-open` to `open` attribute. So the change in `global-open` value changes the `open` attribute too.
Click on the `I change global-open` and see the effect.
I change global-open
My Title
My Description

Events in Component

We have created `toggle-ui` component, now lets add event to this.
-- component toggle-ui:
caption title:
body description:
boolean $open: true

-- ftd.column:
$on-click$: $ftd.toggle($a = $toggle-ui.open)

-- ftd.text: $toggle-ui.title

-- ftd.text: $toggle-ui.description
if: { toggle-ui.open }

-- end: ftd.column

-- end: toggle-ui
Lang:
ftd
We have added an `$on-click$` event and `ftd.toggle` action in `ftd.column` component and pass `toggle-ui.open` argument.
Click on the rendered component below and see the effect.
Input
-- toggle-ui: Click me!

My Description
Lang:
ftd
Output
Click me!
My Description