# Get started with Bravo Studio 👏

Welcome to Bravo Studio Help Center, the knowledge center of documentation, tutorials, and sample files on how to use **Bravo Studio** to create your next native mobile app.

![](/files/V9bsHGafl4Vyzg69yclf)

## What is Bravo Studio?

**Bravo Studio is the piece that connects the design and the backend to build a fully functional app.** Unlike other app builders, Bravo leverages the design and the data handling of third-party tools, adding flexibility to the process. In summary, to create an app we need:

* Figma or Adobe XD to design the UI
* Any backend with a REST API to store the data (Optional)
* Bravo Studio to add functionality by connecting the design with the data. We call “binding” to this process.

![](/files/layYxm9jvR7P0lh8SOqv)

Bravo goes beyond converting a design into an app. It is designed to make, manage and maintain native mobile applications. By working directly with the app design, we can ensure the app remains 100% true to design, whilst dramatically decreasing development time and providing sophisticated functionality.

On the one hand, since **the design part** is leveraged to Figma or Adobe XD you can benefit from the power of these tools in a number of ways:

* They are the standard in the industry, offering lots of features and great UX
* Most designers already know how to use them
* Both have a huge community of users and a lot of learning material

The same goes for **the backend**. With Bravo you are able to connect to any public API and get the data into your app. There are lots of no-code backends that you can use, for example:

* Airtable is an enhanced version of Google Sheets, best for beginners.
* Xano is a scalable and flexible backend, best for low-coders.
* Supabase provides a dedicated database based on Postgres, best for experts.
* Use your own backend. Bravo is great for creating an app when you already have a website.

What Bravo does is to add functionality to your app by connecting the data with the elements of the UI. For this we need to use **Bravo tags**, a list of text strings placed in the elements of your design file, that Bravo converts into native components (both iOS and Android).

## Create your account

Let's start by creating your Starter (free) account to bring your creative projects to life! Begin by following these steps:

1. Ensure you have an active Figma account.
2. Visit [Bravo Studio](https://projects.bravostudio.app/signup) and click on the "Sign Up with Figma" button.
3. Choose to sign up using your Google account or via email and password.
4. Follow the prompts to complete the sign-up process.
5. Congratulations!:tada: Your Bravo Starter account is now ready for use.&#x20;

## Build your first app

Follow this step by step tutorial to learn how to build your first app with Bravo Studio. You will understand how Bravo works and get familiar with the basic concepts: [*Bravorizing*](#user-content-fn-1)[^1], [Bravo tags](#user-content-fn-2)[^2], [*binding*](#user-content-fn-3)[^3] and more:

{% content-ref url="/pages/UGPIrQaqXZvUp9qzcDja" %}
[Create your first app](/get-started/create-your-first-app)
{% endcontent-ref %}

## Need some help?

* [**The Bravo Community**](https://community.bravostudio.app/home)**:** An open forum designed for all Bravo users. It serves as a space for users to ask questions, seek assistance, showcase their projects, and connect with fellow Bravo enthusiasts.
* [**Hire a Bravo Expert:**](https://www.bravostudio.app/bravo-experts) Personalised tutoring and assistance for various tasks, including app development.
* **Email support:** Users on specific plans can report any issues they encounter via email.&#x20;
* [**Bravo Assistant**](https://docs.bravostudio.app/#if-you-cant-find-what-you-need-here-reach-out-for-support): Exclusive to paid users, the Bravo Assistant harnesses the power of AI to provide answers to how-to questions and offers additional support for inquiries.

{% hint style="info" %}
If there are any topics you'd like us to add to our documentation, please share your feedback [here](https://codelesslabs.typeform.com/to/Y180Supl).
{% endhint %}

[^1]: Bravorizing is the process of setting up a design file in Figma to be converted into a native app using Bravo Studio. It involves structuring layers as required by Bravo components and adding Bravo tags for functionality and structure.

[^2]: Bravo Tags are text strings that you place in the component names or layer names of your design file. When you import the design file into Bravo Studio, the layers with Bravo Tags will turn into mobile components or actions in your final app. They allow you to add functionality to UI elements.

[^3]: Binding is the process of connecting data from API requests or the requests themselves to the design of an app. It allows for dynamic and interactive experiences by integrating real data into the app design.


# Create your first app

In this tutorial, you will learn how to create your first app using Bravo Studio using our **Resorts App** as an example.&#x20;

<figure><img src="/files/Pkj2zsSiRy4px23PcsiV" alt=""><figcaption></figcaption></figure>

## What are we going to build?

We are building a simple app with a few screens:

1. A list of resorts
2. A detail page to show more info and images of each resort
3. A [modal page](https://docs.bravostudio.app/bravo-tags/menus/modal-menu)

## Requirements

* Figma for the design
* Airtable for the backend

If you don’t have one yet, **create an account** in each tool:

* [Sign up for free in Figma](https://www.figma.com/)
* [Sign up for free in Airtable](https://airtable.com/signup)

Let’s get started! :clap:

## Step 1: Importing the design&#x20;

As we're using a sample app, we are going to duplicate the design template and connect it to Bravo:

1. In Figma,[ <mark style="color:blue;">duplicate this design file</mark>](https://www.figma.com/file/n8tShV4sOdJAFq0q2R94Oe/Tutorial%3A-Your-first-Bravo-app?type=design\&node-id=0%3A1\&mode=design\&t=RNzmpnf3RdmFk0rG-1) to your account.&#x20;

![](/files/eKzCdaFysSHbnAhufR88)

2\. In your duplicated file, click **Share**, then **`Copy link`**. Make sure the permission for "Anyone with the link" is **`can view`**.

3\. In Bravo Studio, go to [Create a new app](https://projects.bravostudio.app/apps/new).

4\. Paste the link from step 2 into the input field. Click **Connect Bravorized Figma file**.

5\. Once the app is successfully created you will see the app screens imported from your design.

## Step 2: Bravorizing

Now that your Figma design is connected to Bravo, let’s learn a little about bravorizing.

{% hint style="info" %}
We call **bravorizing** the process of setting up your **design file** for being converted into a native app by Bravo Studio. In general, bravorizing consists of:

* **Structuring layers** as required by each Bravo component.
* **Adding** **Bravo tags** to add functionality and structure.
  {% endhint %}

{% hint style="info" %}
Try out our official [Bravorizer plugin for Figma](/set-up-design/bravo-plugin-for-figma) and speed up your app building process!
{% endhint %}

There are a variety of **Bravo components** that you can incorporate into your app: [Menu](/bravo-tags/menus), [Swipe page](/bravo-tags/pages/swipe-page), [Carousel slider](/bravo-tags/containers/container-horizontal-slider), [Modal page](/bravo-tags/menus/modal-menu), [Map](/bravo-tags/map-with-markers), [Form](/bravo-tags/form-and-input-fields), and more. To set up a component, we insert Bravo tags within a specific layer structure. The most elementary tag that Bravo requires is <mark style="color:red;">`[container]`</mark>.&#x20;

[**Containers**](/set-up-design/setting-up-your-design-file/the-container) wrap the UI elements and separate them from each other. You can think of them as blocks. In our first app screen, we have two containers:&#x20;

* Top bar:  <mark style="color:red;">`[container:top-bar]`</mark>&#x20;
* Resort card: <mark style="color:red;">`[container]`</mark>

<figure><img src="/files/J9oJbyan4L2IS4nVR6cM" alt=""><figcaption></figcaption></figure>

Learn more about [Structuring the design and Bravo layer hierarchy](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy).\
\
**Bravo tags** not only work for components or containers, they are also used to add actions to buttons, set the app icon, form input fields, etc. They convert the tagged layers into native mobile elements. Find detailed information in our [Bravo Tags Masterlist](https://docs.bravostudio.app/bravo-tags/bravo-tags-master-list).

{% hint style="info" %}
Explore the layers in the design file and see how Bravo tags are used in the app. We highly recommend using our [Bravorizer plugin for Figma](/set-up-design/bravo-plugin-for-figma) to learn how to bravorize.
{% endhint %}

{% hint style="danger" %}
After making any changes in the Figma file, make sure to click the <mark style="color:red;">**`Update`**</mark> button to sync your Figma file with Bravo.
{% endhint %}

![](/files/8vI7Q2yNl04JpTpUuE9c)

## Step 3: Importing the backend

{% hint style="info" %}
A backend is a server that **stores data and provides APIs** that you can connect to get the information for your app. Think of APIs as an intermediary that allows two applications to talk to each other. In this case, Bravo and the backend, an Airtable database.
{% endhint %}

One of the greatest core values of Bravo is **flexibility**. In Bravo, you can create connections to any backend that provides an API. For our app, we have built a database template in Airtable, one of the simplest (yet powerful) no-code databases.

Duplicate this [<mark style="color:blue;">Airtable base</mark>](https://airtable.com/appFJI5Q2hVrN3D28/shro8btCyXld3G15C) above to your workspace:

<figure><img src="/files/MX1N27qyVIz2phOfN3Xu" alt=""><figcaption></figcaption></figure>

1. Go to [API Collections](https://projects.bravostudio.app/api-bridge) Account Collections and click <mark style="color:purple;">`Create a new collection`</mark>**.**

   <br>

![](/files/w8ZJRZ0oM10c8IGydMGA)

2\. Click <mark style="color:purple;">`Airtable Wizard`</mark>**.**

3\. Go to **Airtable**. On the top right, click <mark style="color:green;">`Share`</mark> → <mark style="color:green;">`Share publicly`</mark> and copy the shared base link:

![](/files/xZnOVnQgTRtDHNxPr9TJ)

4\. Go back to **Bravo** and **paste the shared base link** into the “Enter URL” field. Then, click <mark style="color:red;">`Continue`</mark>**.**

5\. Go to **Airtable** again, click on your account in the upper right corner of the screen. Here you'll see a dropdown menu appear. Click the **Developer hub** option. Or if you are currently signed into Airtable, you can [click here to access the developer hub](https://airtable.com/create/tokens).

<figure><img src="/files/IJZ3hfDw2oSQmU7aeRsN" alt=""><figcaption></figcaption></figure>

6. Click <mark style="color:green;">`Create token`</mark> from the **Personal access token** ta&#x62;**.**
7. Set a <mark style="color:green;">`Name`</mark>, for example: **Bravo API key**.
8. Click <mark style="color:green;">`+ Add a scope`</mark> and select <mark style="color:green;">`data.records:read`</mark> and <mark style="color:green;">`data.records:write`</mark>.
9. Click <mark style="color:green;">`+ Add a base`</mark> and select **All workspaces** (you may select a specific base if you want).
10. Click <mark style="color:green;">`Create token`</mark>. Make sure you verified your email first.
11. A new modal shows up: **Your token has been created**. Copy the token.
12. Go back to **Bravo** and past the token in the <mark style="color:red;">`Enter API Key`</mark> field and click <mark style="color:red;">`Complete`</mark>.

## Step 4: The API collection

Now that you have the design ready and the database imported, we will connect both and add them functionality. First, we need to **create API requests** in Bravo with the Airtable API endpoints:

<figure><img src="/files/fWC84ULCbi4RkNQM0qeZ" alt=""><figcaption></figcaption></figure>

As we have selected the Airtable Wizard option, Bravo created two requests automatically per table: “**List**” and “**Detail**”.

* The “List” request displays all data from the specified endpoint.\
  For more detailed information, refer to the section on [Set up an API GET request for a list page](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/set-up-an-api-get-request-for-list-page-airtable)
* The “Detail” request displays to display data corresponding to the selected item on the previous app screen. Additional details can be found in the section on [Set up an API GET request for a detail page](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-get-request-for-detail-page)

Furthermore, all received data is pre-selected for convenience. Within the Selected Data tab, you can modify the variable names for each of the chosen data sets.

<figure><img src="/files/gY75dTMlCyrI7jPwwSIg" alt=""><figcaption><p>Received data</p></figcaption></figure>

<figure><img src="/files/LXFBS1YBCm2DFm9gTO1h" alt=""><figcaption><p>Selected data</p></figcaption></figure>

## Step 5: Binding

{% hint style="info" %}
**Binding** refers to the process of connecting data from API requests or the backend to the app design. This enables dynamic and interactive experiences by integrating real data into the app. \
\
There are two modes of binding: **static** and **dynamic**. \
\- **Static binding**: Allows using [variables](/connect-api/request-url-variables) from the backend or other API requests.\
\- **Dynamic binding**: while dynamic binding enables real-time updates and interactions with the app.\
\
For additional details, please consult: [Connect data to your design](https://docs.bravostudio.app/data-binding/connect-data-to-your-design).
{% endhint %}

The previous step, selecting the data from the API request, will allow us to assign/bind each data point to its correspondent UI element. Let’s do it!

### 5.1. Binding the list page

1. In **Bravo**, go to **Apps** and open Your first Bravo app.
2. On the left hand side of the screen, you will see your <mark style="color:red;">`Screens`</mark>. Select the "**Resorts list"** page.

![Binding mode](/files/w55ghhvNistfqSwXWrWS)

When you select the Screens, you enter data binding mode. In this mode, you can assign data from the API to each UI element in your design file.

3. Select the UI element labeled "**Resort card**". Alternatively, you can also select the UI element you wish to bind directly from the app image located in the center of the screen.
4. On the right hand side, under <mark style="color:red;">`Element binding`</mark> and <mark style="color:red;">`List Item`</mark>, select the API request  <mark style="color:green;">`GET Resorts-list`</mark> and <mark style="color:green;">`Records`</mark>. This binding will create as many “cards” as rows in the database.

![](/files/OOaWOlCZLF8Wf32obC4E)

We have done our first binding! Let’s continue with the rest of the elements.

5. On the left side of the screen, select the **Resort card** and select the <mark style="color:red;">`*Image`</mark> property. You can also select the UI element you wish to bind directly from the app image located in the center of the screen
6. On the right side of the screen, under **Element binding,** keep the request as: <mark style="color:green;">`GET “Resorts-list”`</mark>  and choose the data point <mark style="color:green;">`images 0 url`</mark> for the Image URL.
7. Repeat the same steps for <mark style="color:red;">`*Name, *Country, *Price and *Rating`</mark>**,** which have the same name for the data points.
8. We have bound our Resort list screen to the backend! 🎉

![](/files/RHakvonq5BM9RUH9ljZw)

### 5.2. Binding the detail page

1. On the left side of the screen, under <mark style="color:red;">`App screens`</mark>, select the **"Airtable - Restaurant detail"** screen and from the data binding section, select <mark style="color:red;">`*Image`</mark>
2. On the right side, under <mark style="color:red;">`Element binding`</mark> section, select the <mark style="color:green;">`GET - "Retrieve restaurant detail"`</mark> request and finally choose <mark style="color:green;">`Field Photo[0] Url`</mark> which corresponds to the image URL.

<figure><img src="/files/eBF7si2BnHsxfonyz8fy" alt=""><figcaption></figcaption></figure>

3\. Repeat the process for the rest of the UI elements with an asterisk \*.&#x20;

{% hint style="info" %}
**Pro tip:** Since we have added an asterisk in Figma to every element that needs to be bound, you can instantly search for all of them by typing an \* symbol in the Search field.
{% endhint %}

{% hint style="info" %}
Learn more about [Bind data to design for a detail page](https://docs.bravostudio.app/data-binding/display-data-in-your-app/data-biding-bind-data-to-ui-for-a-detail-page).
{% endhint %}

## Step 6: Preview your app

It’s time to see our app live! Download **Bravo Vision** from the app store:

* [Download Bravo Vision for iOS](https://apps.apple.com/app/bravo-vision/id1470931833?l=en)
* [Download Bravo Vision for Android](https://play.google.com/store/apps/details?id=com.appfoundry.previewer\&hl=en)

Now open the app and log in using your Bravo credentials. You will see **Your first Bravo App.** Tap to open it.

![](/files/euykrhH41skQFi1XGdKh)

Once you have bound all the elements, the list of resorts should be visible, along with the image, resortt name, short description and cost and if you open a resort, you will see each resort details coming from your backend. 🎉

## Live updates

Another cool feature of Bravo is **live updates**. Once your app is live on the app stores, most of the changes won’t require the users to update to a new version of the app. That includes changing the design, adding new app pages, changes in bindings and more. Your users can instantly enjoy the latest version of your app without any hassle.

## Make it yours

You have completed your first app tutorial with Bravo!:tada: Now you can **keep learning the power of Bravo** by doing changes to the design, adding more content to the database or any idea you come up with. Remember to update the design in Bravo every time you do changes in the Figma file.

![](/files/8vI7Q2yNl04JpTpUuE9c)

{% hint style="info" %}
In case you've skipped step [5.2. Binding the detail page](#5.2.-binding-the-detail-page), you will see that it shows the same content for all of the detail pages (the template content). That is because Bravo shows the design content by default. Bind that screen to fill it with content from the API.  Go back to Bravo Vision and tap on a resort from the Resort list page. You will see that now it shows the correct content. If not, pull to refresh and voilà! 🎉
{% endhint %}

You will find lots of documentation, videos and more in the [Bravo Help Center](https://docs.bravostudio.app/).

Happy Bravorizing! 🎉


# Bravo introduction

Find your way around the **Apps** page in Bravo Studio.

{% content-ref url="/pages/-MkBo7DtgLG-IHbj1vIg" %}
[Create an app](/get-started/your-bravo-app-projects/create-a-project)
{% endcontent-ref %}

{% content-ref url="/pages/-MflFl0o47oOrTYQJGkB" %}
[Duplicate an app](/get-started/your-bravo-app-projects/duplicating-a-project)
{% endcontent-ref %}

{% content-ref url="/pages/-MflGJyCXU\_Q592Ea\_\_K" %}
[Delete an app](/get-started/your-bravo-app-projects/app-projects-deleting-a-project)
{% endcontent-ref %}

{% content-ref url="/pages/-MflH-4TSpFo2rNoV7uX" %}
[The app page](/get-started/your-bravo-app-projects/app-projects-the-app-project-page)
{% endcontent-ref %}

{% content-ref url="/pages/-Medz0aO3QwTD8sLJpPu" %}
[Sharing your app](/get-started/your-bravo-app-projects/sharing-your-app)
{% endcontent-ref %}

{% content-ref url="/pages/-MflJEZfgMLcBsnNQF5D" %}
[Fonts](/get-started/your-bravo-app-projects/app-projects-uploading-custom-fonts)
{% endcontent-ref %}


# Get ready to create your app with ChatGPT

Learn how automating initial development stages can boost efficiency, enhance collaboration, and optimize your project workflow.

### Introduction

{% embed url="<https://www.youtube.com/watch?v=drxs75B8cq0>" %}
Bravo Workflow with ChatGPT
{% endembed %}

In this guide, we will explore how to leverage ChatGPT to automate the initial stages of app development. Emphasizing the importance of thorough upfront work, we will discuss how this can lead to greater efficiency and enhanced collaboration within your development team. We will focus on three key areas:

1. **User Stories:** Ensuring functionality clarity by defining user stories.
2. **Database Schema:** Organizing data effectively through a well-structured database schema.
3. **API Endpoints:** Facilitating effective communication with clearly defined API endpoints.

By using these tools, you can significantly streamline the development process and improve project documentation. Let's dive in and see how ChatGPT can transform your app development workflow!

### User Stories

{% embed url="<https://www.youtube.com/watch?t=8s&v=YIDDAMclQzA>" %}
ChatGPT prompts for Bravo Studio - User Stories
{% endembed %}

#### What Are User Stories?

User stories are brief descriptions of a feature or function from the end-user’s perspective. They help developers understand the requirements and functionality of the app.

#### How to Create User Stories

1. **Identify Key Users:** Determine who will use your app. Common user types include administrators, regular users, and guests.
2. **Describe User Actions:** For each user type, describe what actions they need to perform within the app.
3. **Structure User Stories:** Use the format: “As a \[user type], I want to \[action] so that \[benefit].”

**Example**

* **User Story 1:** As a registered user, I want to reset my password so that I can regain access to my account if I forget my password.
* **User Story 2:** As an administrator, I want to view user activity logs so that I can monitor app usage and ensure security.

### Database Schema

{% embed url="<https://www.youtube.com/watch?t=138s&v=YIDDAMclQzA>" %}
ChatGPT prompts for Bravo Studio - Data Schema
{% endembed %}

#### What Is a Database Schema?

A database schema is a blueprint that defines the structure of your database, including tables, fields, and relationships between them. It ensures data is organized and easily accessible.

#### How to Design a Database Schema

1. **Identify Data Entities:** Determine what data entities (e.g., users, products, orders) your app will manage.
2. **Define Relationships:** Establish how these entities are related (e.g., one-to-many, many-to-many).
3. **Create Tables:** For each entity, create tables with appropriate fields (e.g., user\_id, username, email).

**Example**

**User Table:**

* user\_id (Primary Key)
* username
* email
* password\_hash

**Order Table:**

* order\_id (Primary Key)
* user\_id (Foreign Key)
* order\_date
* total\_amount

### API Endpoints Creation

{% embed url="<https://www.youtube.com/watch?t=280s&v=YIDDAMclQzA>" %}
ChatGPT prompts for Bravo Studio - API Endpoints Creation
{% endembed %}

#### What Are API Endpoints?

API endpoints are URLs that allow different parts of your app or external services to communicate with your backend. They enable data exchange and functionality integration.

#### How to Set Up API Endpoints

1. **Identify Required Endpoints:** Based on your user stories, determine which actions require API endpoints (e.g., user login, data retrieval).
2. **Define Endpoint Structure:** Use RESTful principles to structure your endpoints (e.g., GET /users, POST /login).
3. **Implement Endpoint Logic:** Write the backend logic to handle requests and responses for each endpoint.

**Example**

* **GET /users:** Retrieve a list of users.
* **POST /login:** Authenticate a user and return a session token.

{% hint style="success" %}
We have created custom GPTs with tailored instructions. You can utilize them with ChatGPT 4.0.\
\- [Bravo Product Manager](https://chatgpt.com/g/g-bcJjOGtj9-bravo-product-manager)\
\- [Bravo Technical Architect - Database](https://chatgpt.com/g/g-EoNiJwnJ3-bravo-technical-architect-database)\
\- [Bravo Technical Architect - Endpoints](https://chatgpt.com/g/g-waqRIzDEC-bravo-technical-architect-endpoints)
{% endhint %}

By following these steps—defining user stories, designing your database schema, and setting up API endpoints—you’ll establish a solid foundation for your app development project. This groundwork will enhance your development process, improve team collaboration, and ensure a clear and organized approach to building your app.

Remember, thorough planning and documentation are key to successful app development.


# Create an app

To start an app project in Bravo Studio, you must have the following:&#x20;

1. A [Figma](https://www.figma.com/) account **OR** the [Bravo plugin for Adobe XD](https://www.bravostudio.app/bravo-studio-plugin-for-adobexd)&#x20;
2. A [*bravorized*](/set-up-design/setting-up-your-design-file) design file. **OR** use one of our [sample files](/set-up-design/sample-design-files).

When you have these two items. Go to the **Apps** page > click **Create a new app.**

![](/files/HOwEwW4H8N2KM3lvJOCo)

Once on this screen, follow the tutorials below depending on your design tool to create a new app project.

![](/files/bIHHiDbALEXV9eGPjtH5)

## Tutorials by design tool

{% content-ref url="/pages/-MfgwbNukApTGaf5UCJC" %}
[Creating an app with Figma](/get-started/your-bravo-app-projects/create-a-project/creating-an-app-project-with-figma)
{% endcontent-ref %}

{% content-ref url="/pages/-MfhbBgd0qU1gCkSS7Go" %}
[Creating an app with Adobe XD](/get-started/your-bravo-app-projects/create-a-project/1-adobe-xd-how-to-use-the-bravo-plugin)
{% endcontent-ref %}

{% hint style="warning" %}
Ran into an error while creating a new App? Check out the [import error troubleshooting page](/good-to-know/troubleshoot/errors-when-importing).
{% endhint %}


# Creating an app with Figma

There are two ways to import your Figma file to Bravo: importing it through our platform and by using our Figma Bravo Plugin.

### Creating an app with Figma from our website

Let's explain how to import the following sample design file:

{% embed url="<https://www.figma.com/community/file/1134788542858691041/tutorial-your-first-bravo-app>" %}

&#x20;1\. Go to the **Apps** page, click create a new app.

![](/files/HOwEwW4H8N2KM3lvJOCo)

&#x20;2\. In your Figma file, click <mark style="color:blue;">`Share`</mark>, then <mark style="color:blue;">`Copy link`</mark>. Make sure the permission for "Anyone with the link" is <mark style="color:blue;">`can view`</mark>.

![](/files/2xUj4PxajJiZu95ZbF5t)

&#x20;

3\. Back in Bravo Studio, paste the share link of your Figma file. Click <mark style="color:blue;">`Connect Bravorized Figma file`</mark>

![](/files/8rSKBU3I8EAlAXaVgfS5)

&#x20;4\. Wait for Bravo to do its magic. It's transforming your Figma design into native app screens.

![](/files/6g5en2eRSzF5HVFjC5gd)

5\. Once the project is successfully created from your file, you will see a preview of the app screens created from your Figma file.

{% hint style="warning" %}
Ran into an error? Check out the [troubleshooting page](/good-to-know/troubleshoot/errors-when-importing).
{% endhint %}

![](/files/7JEsAnuHOyFlxHjf3QSg)

&#x20;6\. Check out your app with the [Bravo Vision](/get-started/bravo-vision-previewer) previewer app. 🚀

{% content-ref url="/pages/-MflEqUBYacF9qHsoQL6" %}
[Bravo Vision previewer](/get-started/bravo-vision-previewer)
{% endcontent-ref %}

### Creating an app with Figma by using Bravo Plugin

The Figma Plugin allows you to import your current Figma design into Bravo.

#### :unlock:Sign in from the Bravo Plugin

1. Open your Bravo Plugin and select the <mark style="color:blue;">`Import`</mark> tab.
2. Click on <mark style="color:blue;">`Sign In`</mark> to connect to your Bravo Studio account.

<figure><img src="/files/55Cl9L3wzAciaU04HfHH" alt="" width="375"><figcaption></figcaption></figure>

3. Click on <mark style="color:blue;">`Open browser`</mark> and <mark style="color:blue;">`Confirm`</mark> the given code from the Figma plugin and the opened browser.

<div align="center"><img src="/files/I9KiL2GAYKQXQqiiIRK3" alt="" width="375"> <figure><img src="/files/ec3lJPzJlCjpD6ENUDN2" alt="" width="375"><figcaption></figcaption></figure></div>

&#x20;4\. Once confirmed, this confirmation message will appear. Close the window and return to the plugin.

<figure><img src="/files/1tIBUbFRgEUZu4ZBboQ9" alt="" width="375"><figcaption></figcaption></figure>

#### :new: Create your New Project

5. Click on <mark style="color:blue;">`Create New Project`</mark> to import a new Figma design to Bravo.&#x20;

{% hint style="info" %}
Make sure that your design has at least a frame or a UI element for it to be imported.
{% endhint %}

<figure><img src="/files/RzrjqLba5R3etlKt4gfw" alt="" width="375"><figcaption></figcaption></figure>

6. Wait for Bravo to do its magic. It's transforming your Figma design into native app screens.

<div><img src="/files/02Oj8b931fGEqY38Jy8O" alt="" width="375"> <figure><img src="/files/i0YbeQGzoOCKq7mOUuOZ" alt="" width="375"><figcaption></figcaption></figure></div>

7\. Once the project is successfully created from your file, in Bravo you will see a preview of the app screens created from your Figma file.

{% hint style="warning" %}
Ran into an error? Check out the [troubleshooting page](/good-to-know/troubleshoot/errors-when-importing).
{% endhint %}

#### :repeat: Update your  project

8\. Select <mark style="color:blue;">`Update Project`</mark> to sync your Figma file with Bravo whenever you make any modifications.

<figure><img src="/files/bspgSBt07EZYsqRz1fR1" alt="" width="375"><figcaption></figcaption></figure>

9. In addition, you have the option to create a new project using the same Figma file. Simply click on the <mark style="color:blue;">`Create another new project`</mark> link.

<figure><img src="/files/r9Uc9DskLZHqymGdlhLs" alt="" width="375"><figcaption></figcaption></figure>

&#x20;10\. Check out your app with the [Bravo Vision](/get-started/bravo-vision-previewer) previewer app. 🚀

{% content-ref url="/pages/-MflEqUBYacF9qHsoQL6" %}
[Bravo Vision previewer](/get-started/bravo-vision-previewer)
{% endcontent-ref %}


# Creating an app with Adobe XD

The [Bravo plugin for Adobe XD](https://www.bravostudio.app/bravo-studio-plugin-for-adobexd) allows you to create and update Bravo projects from your Adobe XD file.

{% hint style="warning" %}
This is the only way to **create & update** XD projects with Bravo. You **cannot** connect with an URL or use the "Update" icon in the project page.
{% endhint %}

## 🔓 Sign in from the Bravo plugin

{% hint style="success" %}
Make sure you are logged into [Bravo Studio](https://projects.bravostudio.app/login) before starting.
{% endhint %}

&#x20;1\. Install the the [Bravo Studio plugin](https://adobe.com/go/xd_plugins_discover_plugin?pluginId=310537e8) in Adobe XD.

<div align="left"><img src="/files/-MfhbIxtU0GPw0qprZC7" alt=""></div>

2\. Open a [bravorized](/set-up-design/bravo-best-practices) XD file. Click on the plugin icon in the lower-left corner to access the Bravo Studio plugin.

![](/files/-MfhbIxvS-zDN14eYD4j)

&#x20;3\. Click **Manage Bravo Project** > `Sign in`

![](/files/4BmqpAUv6emOU7qIsEEW)

4\. Click `Open browser`

![](/files/4UeXpOJG6apb5IqA5g0j)

5\. A browser window will open with a code, check if it's the same code that appears in the plugin > click `Confirm`

![](/files/HSQiL6XRvcGZ3zYYUcfz)

6\. Once you see a success page, you can close the browser page and return to XD.

## 🆕 Create a new project

&#x20;1\. To create a new Bravo project with your XD file, click `Create`. Change the project name if you'd like.

{% hint style="info" %}
You cannot change the project name after it's created.
{% endhint %}

<div align="left"><img src="/files/7XOO9b6WbqgltcJz4TWo" alt=""></div>

2\. In Bravo Studio, you will see the newly created project as the most recent project on the **Projects** page.

![](/files/-MfhbIxq2ZEUl4ozrE31)

3\. In the Bravo plugin, you will now see the project appear in the list of projects that you can **update**.

![](/files/uKWUeBXQuJqboTh7RDoB)

{% hint style="info" %}
You can create as many Bravo projects from the same XD file as you want. Just keep in mind that these projects are linked to the same file.
{% endhint %}

Check out your app with the [Bravo Vision](/get-started/bravo-vision-previewer) previewer app. 🚀

{% content-ref url="/pages/-MflEqUBYacF9qHsoQL6" %}
[Bravo Vision previewer](/get-started/bravo-vision-previewer)
{% endcontent-ref %}

## 🔄 Update a project

&#x20;1\. To update a Bravo project with your XD file, select the project from the list of projects that you can update.

![](/files/6Z1Mbef8KuYCWyomTUeD)

2\. Click `Update`

3\. You will see the changes automatically reflected in Bravo Studio and Bravo Vision.

{% hint style="warning" %}
You must update your project from XD, you cannot update from Bravo Studio.
{% endhint %}

{% hint style="info" %}
If you don't see the changes in Bravo Vision, long press (in Bravo Vision) > click `Update with Bravo`.
{% endhint %}


# Duplicate an app

1. In the **Apps** page, **hover** over the app you want to duplicate.
2. Click on the `···` that appears on the top right corner of the app icon.
3. Click `Duplicate`.

{% hint style="success" %}
The app and connected data collections (if any) will be duplicated. Duplicated apps will also keep existing [data binding](/connect-api/data-library-and-binding-complete-collection).
{% endhint %}

![](/files/Rj2ijn4DiChLnPZGwISZ)

That's it! 👏


# Delete an app

1. In the **Apps** page, **hover** over the app you want to delete.
2. Click on the `···` that appears on the top right corner of the app icon.
3. Click `Delete`.

{% hint style="warning" %}
Deleting a project is permanent! There's no turning back!
{% endhint %}

![](/files/IX09RZtuCXUHbWF0cKfZ)


# Replace linked Figma file

You can link your app to another Figma file while keeping the existing bindings. This will enable you several use cases, like having one app for production and another for development or testing new features in a separate app version. Additionally, you can duplicate the Figma file of sample apps and make it your own!

{% embed url="<https://www.youtube.com/watch?v=KHiACqF1akY>" %}

{% hint style="info" %}
If you want to create a separated version of your app, make sure you [duplicate your app](/get-started/your-bravo-app-projects/duplicating-a-project) in Bravo before replacing the linked Figma file. Then you will have two apps linked to separated designs.
{% endhint %}

<figure><img src="/files/83Np1QJSRxc0eaL0GBPp" alt=""><figcaption></figcaption></figure>

1. Open your app and click on the **three dots button** at the top right. For duplicated sample apps, you will also see the option "*Make this app yours*" at the top left.
2. Click on **Replace Figma file**.

<figure><img src="/files/NjRwgmt66cnshjczCZh3" alt=""><figcaption></figcaption></figure>

Now you have to replace your current Figma file with the duplicated one.&#x20;

1. Click on the **current linked Figma file**.
2. In Figma, click file name and select **Duplicate**. If you don't own the file (as in sample apps)  you will see **Duplicate to your drafts** here instead:

<figure><img src="/files/9RII1jQTtv0wSoOyP1YA" alt=""><figcaption></figcaption></figure>

3. Figma will create a copy of the file and show you an "**Open**" button at the bottom. Click on it.
4. In your duplicated file, at the top right, click **Share**, then **Copy link**. Make sure "*Anyone with the link"* is set as "*can view*".

<figure><img src="/files/gNmRXsI0tOeNS5xk6V62" alt=""><figcaption></figcaption></figure>

5. Back in Bravo, pase the link in the **New Figma file URL** input.
6. Click on **Replace Figma file**.

{% hint style="info" %}
Please do not modify the duplicated Figma file. Modifying the structure or layer naming before importing may result in loss of the existing bindings.
{% endhint %}

That's it! 🎉


# The app page

After you import a design file, you will enter the apps page where you configure your app.

## 1. Screens tab

This shows a static preview of all of the screens of your app. If your screen design is longer than the preview size, it will be cropped.

![](/files/Bw4vfe2J8T5ce9RtuB7U)

**Hover** over any screen to enter **Data** **Binding mode**. Where you bind API requests to your app UI.

## 2. Publish tab

Once your app is ready for publication, request your publishable app packages here.

{% hint style="info" %}
Learn about the [publication process](/app-publication/publishing-your-app).
{% endhint %}

![](/files/wK3Y6fEqyGL12vLfL9CA)

## 3. Toolbar

![](/files/B9afnQYDqL8FEEvL2tto)

{% hint style="info" %}
If your project uses an Adobe XD file, icon #1 and #2 will not appear. Sync your project with the Bravo Studio plugin for Adobe XD.
{% endhint %}

**Open Figma file** - Opens the imported Figma file on a new browser tab.

1. **Upgrade App** - If you made any changes in your Figma file, make sure you click here to update your Bravo app.
2. **Update** - Update your latest Figma design.
3. **Notifications** - Notifies you if Bravo detects any setup issue with the design file. They **do not** prevent you from previewing your app, but your app may look different from your design file if they are not fixed.&#x20;

   [Learn more](/good-to-know/troubleshoot/errors-after-importing)
4. **Troubleshoot your app**&#x20;
5. **Preview on Bravo Vision** - Scan the QR code to open Bravo Vision on your phone (if you have it installed) or to open the app store (if you don't).

   [Learn more](/get-started/bravo-vision-previewer)

That's it! 🎉


# Sharing your app

Share your app with others to test and preview on their phone without installation or publication.

### How to share an app by email

Input the email of the app invitee you want to share your app with. Click `Invite`.  The invitee will receive an email that you have shared your app with them.&#x20;

1. Open your app in Bravo.
2. Click on the three dots at the top right of the screen and select the "**Share**" option.

<figure><img src="/files/FUyqwhYG6b04WwktMgxp" alt=""><figcaption></figcaption></figure>

3. In the pop-up, enter the email of the person you want to invite.
4. Finally, click on "**Invite".**

![](/files/98OQgiNhCCSEWNvGCpY4)

5. Et Voilà! :mailbox\_with\_mail: The invitee will receive an email notifying them of the app invitation. We recommend checking their spam folder to ensure they don't miss it.

<figure><img src="/files/IitPITt1USvpy9YYuWYx" alt=""><figcaption></figcaption></figure>

To access the app, the tester needs to download [Bravo Vision](/get-started/bravo-vision-previewer) and create an account **with the email you invited them**. Once logged in on Bravo Vision, they will see your app under "Apps".

![](/files/4is3MuJeJRFY9YCUpf1i)

{% hint style="info" %}
If your invitee log in to Bravo Studio on the desktop with the email address, they will not see your app in their account. The app sharing only allows them to preview the app, not edit.
{% endhint %}

### Manage invitees&#x20;

The emails you have shared the app with will appear below in a list. If the invitee does not have an account with Bravo, the circle icon will appear grey. Once the tester has logged in, the circle icon will turn into a coloured icon with two letters.&#x20;

**To remove sharing permission:** Click the **`X`** next to the email. A confirmation modal will appear. If you confirm, the tester will no longer see your app in their Bravo Vision projects list.

![](/files/zHuLpBQI5lcUYeDHgcZj)

### How to share an app by link

{% hint style="info" %}
This is a premium feature available in **Solo or Team plan**
{% endhint %}

You can also share your app to multiple people with a link. To preview the app, they need to have Bravo Vision downloaded on their phone, but don't need a Bravo Studio account.&#x20;

To get the sharable link: toggle on "**Anyone with link can view**" so it's green. Click "**Copy link**" to copy the link to your clipboard.&#x20;

{% hint style="info" %}
The generated link can be long. We recommend using [Bitly](https://bitly.com/) or a URL shortener to share the link easier.&#x20;
{% endhint %}

You can see how many unique devices has previewed your link. For example, if one person opens your link to preview the app on an iPhone and then a Samsung, it will show "Previewed on 2 devices". This number will include your own device, if you access the app with the link.

![](/files/MvKiaXYk8mDrXvNELRLM)

### Manage link access

If you toggle off the link access, people with the link will not be able to access the app anymore. They will see a message "**Access to this app is denied**".


# Add an editor to your app

{% hint style="info" %}
This feature is only available on **Team plan**
{% endhint %}

Add someone as an editor of the app that you are doing. The Teams plan provides you the flexibility to **up to 10 collaborators** and grant them **Editor permissions** allowing effective teamwork on your app development.

## How to add an Editor to your app?

Here are the steps to add an Editor to your app:

1. Open your app in Bravo.
2. Click on the three dots at the top right of the screen and select the "**Share**" option.

<figure><img src="/files/FUyqwhYG6b04WwktMgxp" alt=""><figcaption></figcaption></figure>

3. In the pop-up, enter the email of the person you want to invite as an editor.
4. By default, the next tab is set to "Preview only". Change it to "**Editor**".

![](/files/AeoqHmG2UYeCuxNOcxyt)

5. To share this app with other Editors, move the collection to the app. Go to [User API collection section](https://projects.bravostudio.app/api-bridge) to change it or simply click on "**Make this app shareable**".

<figure><img src="/files/ugOL2kWUVXW7dDsOMVpP" alt=""><figcaption></figcaption></figure>

5. Finally, click on "**Invite".**
6. Et Voilà! :mailbox\_with\_mail: The invitee will receive an email notifying them of the app invitation. We recommend checking their spam folder to ensure they don't miss it.

<figure><img src="/files/nI8JTUBzbqGKXf2k2czZ" alt=""><figcaption></figcaption></figure>

&#x20;8\. Once on Bravo Vision, they will see your app under "Apps".

![](/files/4is3MuJeJRFY9YCUpf1i)

## Manage invitees&#x20;

The emails you have shared the app with will appear below in a list. If the invitee does not have an account with Bravo, the circle icon will appear grey. Once the editor has logged in, the circle icon will turn into a coloured icon.&#x20;

### **How to remove Editor permissions?**

* Click the **`X`** next to the email.&#x20;
* A confirmation modal will appear. If you confirm, the Editor will no longer see your app in their Bravo projects list.

![](/files/geeBwGH3rjGiwOwrtX4N)


# Fonts

Bravo supports all Figma-supported fonts. If you use a font in your Figma file that is not part of the default Figma font list, you need to upload the font file in Bravo in order to see the font in your apps. Both **.otf** and **.ttf** formats are accepted.

## How to upload a custom font

{% hint style="info" %}
You can only upload a custom font **after** you import a Figma file that includes the font.
{% endhint %}

&#x20;1\. After importing your Figma file that contains a font that Bravo doesn't support, you will see a **"Font Missing"** notification on the app page.

![](/files/kTrQ0ECWsKPwzGlpqsUy)

2\. Click `Fix` to go to the **Font Library** where you can upload the missing font. Here is where you can see all fonts missing and uploaded.

![](/files/rfJH2KAbJq6FMqVo1Q9J)

3\. Click **Upload** to select the font file.

4\. You may encounter a font name mismatch error. This occurs when the font file you uploaded is not the same as the one from your Figma file.

* For ex: two font files can both be Arial Regular, but their postScript names may be "Arial-reg" and "Arial\_Regular." In this case, it is not the same font file.

![](/files/ffLJjErnCzIVJRuzcHd2)

5\. After a successful upload, the font will appear under **Uploaded Fonts**. It also indicates how many apps use this font. You do not need to upload the font again for all future apps using this font.

{% hint style="info" %}
You can replace the uploaded file by clicking `Replace`. Keep in mind that the new file always needs to match the postScript name of the Figma file font.
{% endhint %}

![](/files/6vjjVxEM89iL4ojponUZ)

6\. If you see a `Delete` button next to the font, it means there are no apps using the font and you can delete the font file from your Font Library.

![](/files/TetEBQsrCCDuZGUN6E7J)

{% hint style="info" %}
If you are using an Adobe XD file: learn about supported fonts [here](/get-started/your-bravo-app-projects/app-projects-uploading-custom-fonts/5-adobe-xd-supported-fonts).
{% endhint %}

## How to access the Font Library

There are two ways to access the Font Library.

&#x20;1\. Click on **your username** in the top right corner of the **Apps** page > Click `Access Font Library`

![](/files/YUHdZDHKmWnWv7e4RLmD)

**OR**

2\. After you import a Figma file with a custom font, access the Font Library by clicking `Fix` in the **Font Missing** notification.

![](/files/kTrQ0ECWsKPwzGlpqsUy)

That's it! 🎉


# Adobe XD - Supported fonts

Which fonts are automatically supported and which do you need to upload to Bravo?

## If you have Figma

Any font supported in Figma would work. You would need to install Figma in order for it to be available for XD.

## All other fonts

All other fonts require licenses for you to distribute. Therefore, you must have the font file yourself in order to use them in your apps. If you don't upload the font files, the app will display the text in a generic default font.

How to upload font files: [Here](/get-started/your-bravo-app-projects/app-projects-uploading-custom-fonts). {LINK}

That's it! 👏


# Bravo Vision previewer

Bravo Vision is the previewer app for Bravo Studio. It is where you can preview the native app created from your design file and test all the features implemented in Bravo Studio.

![](/files/7mtgnoJd6OB6tKQJbgur)

### Download **Bravo Vision on your phone**

Download on Android Google Play **👉** [link here](https://play.google.com/store/apps/details?id=com.appfoundry.previewer)

Download on the iOS App Store **👉** [link here](https://apps.apple.com/app/bravo-vision/id1470931833)

## How to use **Bravo Vision**

**To access your Bravo apps:** Log in to Bravo Vision with the same credentials as Bravo Studio.

<figure><img src="/files/briXOIUAg2ocbiaSw3AO" alt=""><figcaption></figcaption></figure>

**To access an app:** On **My apps** screen, tap on an app icon to open the app.

## **Sync app with Bravo Studio**

**To update app with Bravo Studio or to refresh:** *Long press* the screen to activate the menu, tap `Sync app with Bravo Studio`.

<figure><img src="/files/zhu6QcUwlVLIjBkvAMuX" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
In the activated menu, tap **"Disable automatic sync"** so that whenever you update your project in Bravo Studio, Bravo Vision will also update.
{% endhint %}

![](/files/dC5p33RlMAzkrFivmLv1)

## **Copy app page url**

In order to get that URL, load the app in Bravo Vision, navigate to the page you want, long-press anywhere and click **Copy app page URL** (a share dialog will open so that you can send the URL using your preferred method).

<figure><img src="/files/1THpK34NihMH9qSF5tgR" alt=""><figcaption></figcaption></figure>

## **Open troubleshooting tools**

The Open troubleshooting tools will open the log with the latest events. The [**Event logger**](https://docs.bravostudio.app/connect-api/debugging-api-issues/event-logger) tool will allow you to debug and find the root of the API errors you encounter on **Bravo Vision**, as well as give you more visibility on the actions performed in the app while previewing it on Bravo Vision. For more details go to[ **Event Logger**](https://docs.bravostudio.app/connect-api/debugging-api-issues/event-logger)**.**

<figure><img src="/files/ruwXxwj8ikDVTO3Ly2nP" alt=""><figcaption></figcaption></figure>

## **Exit app**

**To exit the current app:** *Long press* the screen to activate the menu, tap `Exit app`.

<figure><img src="/files/LfRXj0VR29Qu2WeJrwP1" alt=""><figcaption></figcaption></figure>


# Unlock power features to create interactive apps

Upgrade your free account to the Solo plan to add interaction to your app

[Start your 7-day trial](https://www.bravostudio.app/pricing) into the Solo plan to create powerful apps by giving power to the app users. Add functionalities that allow your users to engage and customise their experience with the app content. Take these steps to upgrade your app project!

![](/files/7yJnJRdL7IHCZLpPU7P6)

### Implement unlocked features

Take advantage of these premium features to add user-interactivity & advanced content configuration to your apps.

* [Create, edit & delete data with your app](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6Qr05zw0asqOKsYj56bED8diiRFl-2BsN9tnUnTzdSx-2BoxMA89OEdIYoTaUzG9HvDE3mWvnRygoMDajha6MBnOhbQ-3DETY5_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071INa8MGS-2BAcZQ5lfKtxJx237aJqf1-2FLrxVvUyn0cbYY4ooTsq72z0ZI0lW-2B9hr079Pl6abxYEOgqGx8UfkqH9ixfM1GNvhVCQ4yGxCfDeLrOt6slQGQJLtq3UVTAP125RwfsA1ADcZDy4QXXBoV6skZc-3D)
* [Multiple requests per screen](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6Qr05zw0asqOKsYj56bED8diiRFl-2BsN9tnUnTzdSx-2BoxN0gl3WYvjrIkD59R6llWgBGDM-2BevSoQJiWoaVHFRiX-2BH4-2BMG-2FaBzx55fdnSePoy7HS4g4ZNStKDHBVP1GCJgskbjV6gPJPiQ51KCJNx-2Bx9A-3DnKaz_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IDscZQ67oMJ2eOcjLc-2B-2BilVrXu2M-2B86os7DXQRLWmR2YWgFC8PzPPsTKUmxesSh2WGD8qoXKLHg5p5zT4705WBC4zC9yslol7gMFS4dV-2Frlc5f9KQ5PSoXlM53irlLDBW94SxFNhP5bVsE9MAnFGCbQ-3D)
* [Conditional visibility](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6Qr05zw0asqOKsYj56bED8eeUi8JmOxYsPweTs4njl8dnJgwMkSMFHKuGMMOZLtmfTZBX-2FQMdPXQM8cJW1wJZh4-3D65l1_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071INeEPMUXflck-2Byo9OFiDyoBI3EZGsQkvAoetMnRs5RxmZUXOeFkmCrE-2F4N574w13TxzGi0Nj7FYX12pZ-2FOE337blV-2FHmFSUA2SkHpeY7u1hR4YBE4YEW1GOJK-2BgkeLAywHjuqeD87mmQb9FLR9G7VxA-3D)
* [Login & authentication](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6Qr05zw0asqOKsYj56bED8clhRTQOMHQ1djSNDenphf-2BAxyMv4JpgbAjyc4j-2Bp4hkdJ0azT8ajKOtAey99MhDJM-3Dl_uS_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IGRYqZudNojdEsrAafk3sbTGVLhsY7fYGjuAnOtqiYCdGWzBNQsUUOE9vEz3pXEBcOPv3lXXQm9J7DuA3jin1q-2FdziuiuF62RoVbtAk0AVNnoPJxQHhh-2B5zvVue3xvyWmsMIa-2Bjrec6rpPI2B4p5xX8-3D)

{% hint style="info" %}
Check out the [full list of features](https://www.bravostudio.app/pricing) of the **Bravo Solo** plan
{% endhint %}

### Advanced Apps add-on

If you subscribe to the Bravo Solo plan, you’ll be able to add to any of your apps an Advanced app add-o&#x6E;**.** Advanced app users benefit from our [**versioning feature**](/app-publication/versioning) to control when to push changes to their published app and publish whitelabelled apps (no Bravo's branding). You can have as many Advanced apps as you need!

Our Advanced pricing options include **89€ per app per month** or a discounted rate of **890€ per app per year (2 months free).**

[Check our plan comparison and FAQ.](https://www.bravostudio.app/pricing)

![](/files/0hithdnEZrG8zD689YqF)

### Use design & backend templates

Speed up your app building by starting with these ready-made setup, then customise them to your app case.

* [Task list app](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6dUymw9FC0gmc-2F6dBV9SLE5Q28aExsoWOJ0C6PwOYH2zHLHW67spYdDR51A6jkcogM3qgQ0uDv56FZhpX2p6XjbHfplbzGlUisfM0TGfMiWWR-2FFRkYyA5SinXu8eO1lyGg-3D-3Do8D7_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IJC-2FxuKOUsPBNQpVuZWB2vzyuznRiTBk1aSrUeLZuOeoZzjaQ4QF5SKRsAQuw95JuPj25wi-2FPDFx07YsYRynY72JGvqIUWXztbMnrFXELO2aFVBGOdkdwbr7u7vMwgUUP2vzrZR3khrtel4P-2B73bY8I-3D)
* [Home rental app](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6dUymw9FC0gmc-2F6dBV9SLE5Q28aExsoWOJ0C6PwOYH2zHLHW67spYdDR51A6jkcogHzjWqbdz0JQbaiy7hVxcQBLXqnGcyClY1-2BNsnplV5-2F8APgwaOjXnuPXWzdHmuwjKw-3D-3DC5iq_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IKa-2FmSI9zEiJg5SjUg0RXLaENfvtjaU-2F9X-2F5-2F1iwnOohRjgKAdrBWwDLPL0zCoBBBOVa6Tizq-2BFoahQ8theSl8wHPyJK-2BxewkJvqIFfjsxuVZxN1jw2OO1wPZU-2F9DojOalzVXvTxmJWOhGYhQgEBV8k-3D)
* [CRM (customer relationship management) app](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6dUymw9FC0gmc-2F6dBV9SLE5Q28aExsoWOJ0C6PwOYH2zHLHW67spYdDR51A6jkcogKkSjzFP-2FTGZuUKv3X8CYpsWcHxKXvPE7-2BG4gvhVtDUhmLgErZD3AEMsqXzxj83I3w-3D-3DCKl3_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IL1Ek5Y72eSLNilOM-2FY-2FDCPatgWwrG0Q6J5sF1JTF8rrt1Gh-2B4CCKIlhaTuuhIxG-2FwWEJsOgt8McfI2n-2FWwhQgBnAZaLUinwfWfyoc3c6Ub5IUucGyhYVE5mAU4H8eZ54t2mzPZyKOEe-2BlgNnNRks2I-3D)
* [Basic app template](https://projects.bravostudio.app/sample-apps/complete-apps?appId=01G1SWPZTN14MMKC12QFZRKHQA)

### How to upgrade my account?

There are two different ways to upgrade your account to Bravo Solo:

* Upgrade from the [Bravo dashboard](https://projects.bravostudio.app/pricing).
* Upgrade inside Bravo Vision iOS. The upgrade pop-up will appear for every second app you close in Bravo Vision.

### We’re here to help if you get stuck

It’s ok to not understand everything right away, here are the resources to help when you encounter these moments.

* For Bravo Solo users: Ask our support team via email (Click the ? icon at the bottom right corner when you’re logged in to send a message)
* For all users: [Consult fellow Bravorizers in our community](https://u10116659.ct.sendgrid.net/ls/click?upn=3xmvTAY21KaJKFw1lnlH6fvvqRmK9XaZkupkWo4u1rk-2BGxA0OaG3g5f1ROoWLX9z1CLj_rlGrpn7c-2B6j1xg3ShZ2gajisc6whxQndXWpcZ-2Fmz-2BRlSBjBOZUM9TPMvrfXv814OBptZxf0Q3iJtQKFAaA6LvNdof5LFx1I5zMBlHmDIt3duYVa-2BNjC11Xt8CQ4jcUhJQWs5mnrtS75TJQx-2Bkb6y3iSBiu1BgS6xtH9EoG5-2Fsaf1OtPiZmkBBZuFPg9JdHGNNhIT8stBBgmyCjrx-2FsH5IZNMkPoRhFNbQsqZUx1lKvFV-2BiUzErUxudkQXQqOZsdj6-2Fw7-2FjcJUEWALSW6GyXrt-2BofGJ9NT3mn8-2Bxq79UhAnjUVcivo5AJq5rgZwIMaJhpDcifuR-2BwIO5FgENRK-2BtY23-2FDLpkHVtMGl93E5apGpCGbp3PC6rnwkS0Vcjt6Ubs9NT14UUMTaCK-2FXz4-2F0071IG7-2BYhhIdFn4YWgAfnzWKR-2FmQ1iqPQZOxIvfHU7eIPMPtZNwFtcB9HJMCc-2FNBKPoRSmhNIvT-2Bl2-2BJWaJBAdpyYmKiUgxZPvf0nTehtoUrVqd854vSgsDZh8onOuxq0v-2FzVaUJwWRANy7h4PUQFO90Fs-3D)


# Help and tutorials

Tips for contacting support and accessing further resources

## Bravo guide videos

Beginner:

1. [Intro to Bravo](https://www.youtube.com/watch?v=mM4HvlzC6Uw)
2. [Intro Webinar with Bravo Team](https://www.youtube.com/watch?v=sk-ZniZiGAk\&t=140s)
3. [Convert your Figma File for Bravo](https://www.youtube.com/watch?v=A_Ih0ETwMa0)
4. [Beginner Masterclass | Figma Basics for Bravo Studio](https://www.youtube.com/watch?v=VhmigPg6CvM\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=1)
   1. [Bravo Menus 1/5 video](https://www.youtube.com/watch?v=DHzyHGSbDwM\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=2)
   2. [Bravo Top bar 2/5 video](https://www.youtube.com/watch?v=gIhqDss03I4\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=3)
   3. [Bravo Lottie 3/5 video](https://www.youtube.com/watch?v=ac3H08n5dPo\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=4)
   4. [Bravo List pages 4/5 video](https://www.youtube.com/watch?v=EIooA1BVZgI\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=5)
   5. [Bravo Figma prototype 5/5 video](https://www.youtube.com/watch?v=SvZy3k05qpk\&list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG_\&index=6)

Advanced

1. [Variables in Bravo](https://www.youtube.com/watch?v=PLcgXR1OoAc\&t=298s)
2. [Build an Airbnb app with Xano](https://www.youtube.com/watch?v=SPKdCa57Lno)
3. [Build a Fitness app](https://www.youtube.com/watch?v=7eSzOy74iVM\&t=12s)
4. [Build an AI StoryBook app with Rowy](https://www.youtube.com/watch?v=_v8Wi2cy1T8\&t=360s)

***

## Get Help

#### AI assistant bot

Get AI-powered help by pressing (?) in the app and asking your question to our AI-powered bot. Support is a difference in our plans. Paying users can report an issue directly on the (?) chat and will be directly reported to Bravo support.&#x20;

#### Bravo community&#x20;

We also recommend joining our [community](https://community.bravostudio.app/home) to meet other Bravo users and exchange tips. The Bravo team is in the community too so we can help you there so others to benefit from your question.

The community is also a good place to report bugs, share product feedback, request a feature, ask for help when building integrations and working with the APIs, and get help from Bravo or the community. For faster responses, check other [options here](https://www.bravostudio.app/production-support-bravo-studio).

#### Contact sales

[Speak to our sales team](https://www.bravostudio.app/form) about plans, pricing, and company contracts, or request a demo.


# App guide tutorials

See how to build full app functionalities with these articles and tutorials.


# Sample app tutorial: Your first binding

Learn the essentials of Bravo with this beginner's tutorial.

<figure><img src="/files/wyMhWpRjhAGm5wDdbCFn" alt=""><figcaption></figcaption></figure>

*We're continuing our journey with Bravo in this next part of the quick start guide.*

Great! You've made your first bindings in Bravo. Essentially, you've connected the design with the backend. This sample app is connected to Figma for design and the data comes from Xano. We'll cover them later, so for now let's continue binding the rest of screens.

1. In Bravo, go to **Apps** and open the **Sample app: Your first binding**.
2. On the left column, click on the app screen named **Resorts list.**
3. Select the **Resort card** container. You can do it in two ways: Directly on the app preview at the center, or on the Data binding section at the left panel.
4. On the **List item** property at the right panel, select the collection **Sample app: Your first binding**, then the request called **List of resorts** and the item called **data**.

<figure><img src="/files/kf4fRA2xwVyxZE287qlq" alt=""><figcaption></figcaption></figure>

Awesome! You've just bound a list of elements (*data*) to a container (*Resort card*). Now the app will show as many "cards" as rows returned by the request in the database.

Let's continue binding the content of the card:

1. Click on the image and, on the Image property at the right panel, select **List of resorts -> img url.**

<figure><img src="/files/aS3siwkbXiElstZnTINY" alt=""><figcaption></figcaption></figure>

2. Repeat the process for **\*Name**, **\*Rating**, **\*Country** and **\*Price**.

## Preview your app

It’s time to see our app live: Download **Bravo Vision** if you don't have it already:

* [Download Bravo Vision for iOS](https://apps.apple.com/app/bravo-vision/id1470931833?l=en)
* [Download Bravo Vision for Android](https://play.google.com/store/apps/details?id=com.appfoundry.previewer\&hl=en)

Now open the app and log in using your Bravo credentials. You will see our app **Sample app: Your first binding**. Tap to open it.

On the home screen, click the button **Go to list of resorts** to see the actual data that come from the database. Bravo! 🎉&#x20;

![](/files/vwAYh4aUA1yLiTKyYdVB)

Now open a couple of resorts. You will see that it shows the same content for all of the detail pages (the template content). That is because Bravo shows the design content by default. Let’s bind that screen to fill it with content from the API.

1. Go back to Bravo Studio and open the **Resort detail** page.
2. Select *Trip card → \*Image.* On the property “Image” at the right panel, select **Resort Detail** → **img url:**

<figure><img src="/files/rLCgO9sIdpnSAxWPOS4I" alt=""><figcaption></figcaption></figure>

3\. Repeat the process for the rest of the parameters with an asterisk \*.&#x20;

{% hint style="info" %}
**Pro tip:** Since we have added an asterisk to every element that needs to be bound, you can instantly search for all of them by typing an \* symbol in the Search field.
{% endhint %}

Once you have bound all the elements, go back to Bravo Vision and tap on a resort from the list of resorts page. You will see that now it shows the correct content. If not, pull to refresh and voilà! 🎉

## Make the app yours

If you want to go further, you can replace the Figma design with your own by duplicating the file in Figma and using the **Replace Figma file** option. You will find the instructions there:

<figure><img src="/files/qx1IGMc2X9lG4rKWuiYv" alt=""><figcaption></figcaption></figure>

If you want to own the backend piece, you can clone [this Xano snippet](https://www.xano.com/snippet/LoGWgwk9) and replace the host name part of the urls of all requests:

<figure><img src="/files/uPG1ZtAYsyl1Igo9qhjx" alt=""><figcaption></figcaption></figure>

## Live updates

Another cool feature of Bravo is **live updates**. Once your app is live on the app stores (or on Bravo Vision), most of the changes won’t require the users to update to a new version of the app. That includes changing the design, adding new app pages, changes in bindings and more. Your users can instantly enjoy the latest version of your app without any hassle.

## Keep going!

Our app is complete! Now you can **keep learning the power of Bravo** by doing changes to the design, adding more content to the database or any idea you come up with. Remember to update the design in Bravo every time you do changes in the Figma file.

![](/files/IH8FTyUcLTieWV0255Mj)

You will find lots of documentation, videos and more in the [Bravo Help Center](https://docs.bravostudio.app/).

Happy Bravorizing! 🎉


# How to build a Fitness app with Bravo, Xano and RevenueCat

<figure><img src="/files/yHB9puXEOJ9VSQf11TxA" alt=""><figcaption></figcaption></figure>

In this tutorial we are going to explain how to build a Fitness app with Bravo Studio, Figma, Xano and RevenueCat. The app will allow users to explore workout videos and food recipes as well as subscribe to premium content.

Some of the features of this app are:

* [Custom login with Xano](#set-up-custom-login-with-xano)
* [Like button](/bravo-tags/components/stateful-component-like-button)
* [Map](/bravo-tags/map-with-markers)
* [In-app purchase](#set-up-in-app-purchase)

{% embed url="<https://www.youtube.com/watch?v=7eSzOy74iVM>" %}

## Requirements

* [Figma account](https://www.figma.com/) (free)
* [Xano account](https://app.xano.com/admin/signup/bravostudio) (free)
* Bravo Solo plan + Business app (218€/month)
* [RevenueCat account](https://www.revenuecat.com/) (free)
* [Apple developer account](https://developer.apple.com/) (99€/year)
* Some knowledge about APIs and database relationships

## The design

<figure><img src="/files/XmVp6s3sZNQx3R44kcYN" alt=""><figcaption></figcaption></figure>

First of all let’s have a look at the design: [Bravo Use Case: Fitness app](https://www.figma.com/community/file/1217435722039388173)

You can see the design is fully bravorized with containers and Bravo tags, the navigation is set up and the layers that will be bound to real data contain an asterisk (a little trick we do to speed up binding process later). Feel free to explore the design and learn how it’s been built.

For example, check out the Paywall screen. The CTA layer contains the tag <mark style="color:red;">`[action:purchase:full]`</mark> which allows the user to trigger the purchase action of the “full” subscription. Inside it, we have a text layer with <mark style="color:red;">`[price:full]`</mark> and <mark style="color:red;">`{price}`</mark> within the text, which shows the app user the corresponding price of the subscription.

Let’s duplicate the design and make it of your own.

<figure><img src="/files/Ol1Q0Rcy9gMH9sllzZQ0" alt=""><figcaption></figcaption></figure>

1. In Figma, [duplicate this design file](https://www.figma.com/community/file/1217435722039388173) to your account
2. In your duplicated file, click `Share`, then `Copy link`. Make sure the permission for "Anyone with the link" is `can view`.
3. In Bravo Studio, go to [Create a new app](https://projects.bravostudio.app/apps/new)
4. Paste the link from step 2 into the input field. Click `Connect Bravorized Figma file`
5. Once the app is successfully created you will see the app screens imported from your design.

{% hint style="info" %}
Make sure your account plan is Olé and you have upgraded to Business app in order to follow the tutorial successfully.
{% endhint %}

## The backend

For the database and API we are using Xano, one of the best no-code tools that you can connect to Bravo and launch a complete backend in minutes.

{% hint style="info" %}
Bravo users enjoy a **10% discount on any Xano package** if you sign up from our referral url -> <https://app.xano.com/admin/signup/bravostudio>
{% endhint %}

One of the coolest features of Xano are snippets. Snippets allow you to clone a complete backend to your own account with just a click, including database entities, data records and API endpoints. We have a complete backend already set up for this tutorial! Awesome, right?

1. Open this snippet.
2. Click on “**Add to your Xano account**”.
3. Login and add it to your Xano instance.
4. From your Workspace, open the Marketplace tab and select the Purchased section.
5. Once selected, you can review the Snippet and click to install it to your Workspace.
6. If you have any trouble, check out the full docs on [how to add a snippet](https://docs.xano.com/xano-features/snippets/preview-and-add-a-snippet).

<figure><img src="/files/kXYtVCAXoEnKd6GvIHBB" alt=""><figcaption></figcaption></figure>

The database consists of six tables:

* Fitness\_workout
* Fitness\_workout\_category
* Fitness\_user
* Fitness\_user\_recipe
* Fitness\_recipe
* Fitness\_spot

These tables already contain data records for your convenience. For example, *Fitness\_workout* contains the list of workouts with title, description, video url and other fields. This table is connected to *Firtness\_workout\_category* by *category\_id*. Feel free to checkout the rest of tables and how they relate to each other.

{% hint style="info" %}
If you are not familiar with database relationships, you can learn the basics with [this tutorial from Xano](https://docs.xano.com/database/database-relationships).
{% endhint %}

Now let’s take a look to the API endpoints.

1. Open the **API** tab from the left menu
2. Click on **Fitness Use Case**

You will see a bunch of API endpoints grouped by name. Some of them include custom filters and rules. For example, open */fitness\_workout\_featured.* The endpoint queries all workouts where *isFeatured* is true and *isPremium* is false.

Please note that authentication is required for all endpoints (except */auth/signup* and */auth/login*), which means that the request must include the auth token in the headers for it to run successfully. We'll go over this later, but for now this will give you a sense of the power of Xano 🔥.

## Set up custom login with Xano

Now that we have our design connected to our Bravo app and the backend is ready, we can proceed with connecting both by configuring app authentication.

Bravo Studio supports different methods for authenticate users into your app: OAuth 2.0, Firebase login and Custom Authentication. The latter is the method we will use to configure Xano.

<figure><img src="/files/ec5Jo9xxrZE7zo7HcMBs" alt=""><figcaption></figcaption></figure>

Since our Xano Snippet already has the necessary endpoints, we’ll go to Bravo and connect them to our app. If you want to set it up from scratch, learn [how to set up Xano as your user authentication backend](https://docs.bravostudio.app/integrations/user-authentication/authentication-with-custom-backend/set-up-xano-as-your-user-authentication-backend).

1. In Bravo, go to **API Collections → Create a new collection**
2. Select **Xano Wizard**
3. [Go to your account](https://app.xano.com/admin/account) in Xano and copy **Your Private Developer API Key**
4. Go back to Bravo and **paste the API Key** in the input field
5. Click **Continue**
6. Select the **instance** that contains the cloned snippet and **Continue**
7. Select the **Fitness Use Case** API group and **Continue**
8. Now you’ll see the list of endpoints. Click **Select all** and **Continue**

🎉 Congrats! You have imported the API endpoints to Bravo.

Now we’ll need to do some important tweaks to finalise the set up.

1. Select the request named **Auth · Login**
2. Select **Test Values** tab
3. For **email**, set **<test@test.com>** as value
4. For **password**, set **12345678**
5. Press **Send**
6. Go to **Selected Data** tab and change the **Variable Name** from “authtoken” to **accessToken**
7. Go to **Received Data** tab and copy the value of the token (a long string usually starting by “ey”)
8. Click on to the **wheel icon** nearby the API Collection name

<figure><img src="/files/bYIoybUHrPEA47ilqTEA" alt=""><figcaption></figcaption></figure>

9. Go to **Authentication** tab and select **Bearer**
10. Paste the copied token in the **Token** field and click **Save**

Now all of the requests sent on this screen are authenticated. If in the future the auth token expires, you’ll need to repeat the steps 5 to 10.

## Auth tags

<figure><img src="/files/dON5P98E7gWpArRiHWL9" alt=""><figcaption></figcaption></figure>

Let’s review how the login screen is *bravorized*. First of all, it has a <mark style="color:red;">`[page:login]`</mark> tag in the top-level frame and a <mark style="color:red;">`[post-login:action]`</mark> tag that we’ll cover later.

We also have two textfields with form tags: <mark style="color:red;">`[component:input-email]`</mark> and <mark style="color:red;">`[component:input-password]`</mark>. To submit the form we have a [stateful component](https://docs.bravostudio.app/bravo-tags/interactive-component/stateful-component-like-button) with two states: *default* and *pressed*. The first has the submit action for login forms: <mark style="color:red;">`[action:login]`</mark>. Learn more about [forms and input fields](https://docs.bravostudio.app/bravo-tags/form-and-input-fields).

So, now that we have the design ready it’s time to bind it to the backend.

## Binding

<figure><img src="/files/oOvwZkMlQx5Zw32ZcUAo" alt=""><figcaption></figcaption></figure>

We are going to set up authentication connecting the design elements with the auth API requests that we imported before.

1. In Bravo Studio, open your app and enter the **Data binding** screen
2. On the left panel, select \***Email** element
3. Open the **Input Destination** panel on the right
4. Select **Fitness Use Case** → **Auth · Login** → **email**
5. Repeat with \***Password**. Select **password**

Now both variables are bound to the input elements.

<figure><img src="/files/VjOVLOvg7VlVW2vMfk0A" alt=""><figcaption></figcaption></figure>

We’ll proceed to set the token returned by the login request to the **accessToken** variable:

1. Select the *default* layer under the *CTA* frame on the left sidebar
2. Open the **Form response action** panel on the right
3. Select **Set Access Token** in the **On Success** dropdown
4. Type **${accessToken}** in the input below it

You’re all set!

## Bravo Vision

It’s time to test the login! [Download Bravo Vision](https://docs.bravostudio.app/get-started/bravo-vision-previewer) if you don’t have it already.

1. Open Bravo Vision and login with your Bravo credentials
2. Open **Fitness Use Case** app
3. Continue the intro page
4. In the login page, enter **<test@test.com>** as email and **12345678** as password
5. Click the **LOGIN** button and you should be logged in!

## Binding the home page

<figure><img src="/files/FbM1ZMOXLOmJRIkXU4NN" alt=""><figcaption></figcaption></figure>

The home page has three elements bound to API requests:

* List of categories → **Workout categories · List**
* Premium workout card → **Workouts · List premium**
* List of workouts → **Workouts · List**

Let’s connect the visual elements to the data!

### **List of categories**

1. Select **Category slide** on the left sidebar
2. Open the **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts categories · List** → **data**
4. For \***Name (IMAGE)**, select the same request and the **image url** param for the **Image** property
5. Repeat for \***Title,** select **name** for **Text**

### Premium workout card

1. Select **Premium workout card** on the left sidebar
2. Open **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts · List premium** → **data**
4. Bind \***Background image (IMAGE)** to **video\_thumbnail url** for **Image** property
5. Repeat the binding to match the following:
   1. \***Workout short description** to **description**
   2. \***Workout title** to **title**
   3. \***Workout category** to **category name**

### List of workouts

1. Select **Featured workout card** on the left sidebar
2. Open **List Item** property on the right
3. Select **Fitness Use Case** → **Workouts · List Featured** → **data**
4. Repeat steps 4 and 5 from previous binding (Premium workout card)

Now go to Bravo Vision and refresh the homepage, you will see the elements returned by the database 🎉

{% hint style="info" %}
For this tutorial we are not covering the complete binding of the app. Feel free to explore the API requests and continue the process on the rest of the app screens. If you have any question feel free to [ask it in the Bravo community](https://community.bravostudio.app/).
{% endhint %}

You’ll have seen that we bound the premium content, although for the moment every user will see it, and that’s not what we want to happen. It’s time to configure In-app purchases!

## Set up in-app purchase

<figure><img src="/files/eznaZNmO5sBvqAkXBg7V" alt=""><figcaption></figcaption></figure>

To allow app users to purchase subscriptions, Bravo integrates RevenueCat, a platform that provide a subscription backend and wrapper around Apple's StoreKit and Google Play Billing. With RevenueCat you can make sure your users pay for accessing specific pages and content. Instead of having one set up for Android and another for iOS, Bravo connects to RevenueCat to have both platforms available in your app with just one connection.

<figure><img src="/files/OrevxMltqzEyE4JDqyfd" alt=""><figcaption></figcaption></figure>

Our app will be able to do the following:

* Show Upgrade buttons to free users
* Show a paywall to unlock paid content, showing the price from the AppStore of GooglePlay (in the user’s currency)
* Show a list of premium workouts to paid users

## App Store Connect configuration

{% hint style="info" %}
We are not covering the Android/Google Play set up. Check out the [full in-app purchase documentation](https://docs.bravostudio.app/integrations/in-app-purchases-and-subscriptions-revenuecat#setup-revenuecat-app) to learn more.
{% endhint %}

First off we need to create an app in App Store Connect and generate some codes:

1. Follow step 2 from [our iOS publication guide](https://docs.bravostudio.app/app-publication/publishing-your-app/ios-publication-complete-process) (step 1 is optional) to generate the Certificates, Identifiers and Profiles.
2. Go to App Store Connect's [My Apps](https://appstoreconnect.apple.com/apps) page and click on the **+ button** → **New app.**

<figure><img src="/files/4bWZD8V5DNbJgGEw7xwz" alt=""><figcaption></figcaption></figure>

1. In **Platforms** select **iOS.**
2. Set a **Name** and **Primary Language.**
3. Select the Bundle ID generated previously.
4. Set an **SKU**. For example a date: *20230312.*
5. Select **Full Access** (it’s up to you though) and click **Create.**

### Generate subscription

Your app has been created! Now let’s generate the subscription.

{% hint style="info" %}
To keep things simple, we are going to create just one subscription for this tutorial. If you want to create more, check out [RevenueCat’s documentation](https://www.revenuecat.com/docs/ios-products).
{% endhint %}

1. In the sidebar, select **Subscriptions** under Features, then click the **+** button to create a Subscription Group.
2. Set *Fitness premium* as **Reference Name.**

<figure><img src="/files/dPPkEQevGzvymAGVP7J9" alt=""><figcaption></figcaption></figure>

3. After creating your Subscription Group, click the **+** symbol to add a new subscription to the group.
4. Set *Full access monthly* as **Reference Name** and *fa\_699\_1m* as **Product ID.**
5. Click **Create.**

{% hint style="info" %}
The product Id is a unique alphanumeric ID that is used for accessing your product in development and syncing with RevenueCat. After you use a Product ID for one product in App Store Connect, it can’t be used again across any of your apps, even if the product is deleted. It helps to be a little organized here from the beginning - we recommend using a consistent naming scheme across all of your product identifiers such as:

**\<app>\_\<price>\_\<duration>**
{% endhint %}

### **Set subscription duration**

Once your product is created, you'll be able to set the duration of the auto-renewable subscription. Use the duration dropdown to choose **1 month**, and click **Save**.

### **Set subscription price**

1. Click **Add Subscription Price** in the **Subscription Prices** section.
2. Select your desired **Country or Region** and 6,99 as **Price**
3. Click **Next.** Apple will automatically set the price in all App Store regions based off the price and currency you selected. You'll have the option to edit these, but we recommend sticking with the defaults. When done, click **Create**.
4. Click **Save.**

### **Adding Localization**

This is the name and description of the in-app purchase that the user will see.

1. In the App Store Information section, click the '**+**' icon next to Localization
2. Set *Full access* as **Display Name**
3. Set *Get access to all videos and recipes* as **Description**

The Subscription Display Name and Description **will be visible to the user** on the App Store and in their subscription management settings

### **Reviewer Information**

Since we are just testing the set up in Testflight, we will skip this step. You’ll need it once you want to get your app published.

### Subscription Groups

When you configure products for the first time and just set up a subscription group, you may see a warning in App Store Connect:

> Before you can submit your in-app purchase for review, you must add at least one localization to your subscription group. Add localizations

Clicking on the **Add localizations** link will take you to the Subscription Group configuration. Similar to how you added localizations to the product, you'll need to add localizations to the Subscription Group as well.

Don't forget to click **Save** before exiting.

### App-Specific Shared Secret

Generate an App-Specific Shared Secret [following this guide](https://www.revenuecat.com/docs/itunesconnect-app-specific-shared-secret).

### In-App Purchase Key

Generate an In-App Purchase Key [following this guide](https://www.revenuecat.com/docs/in-app-purchase-key-configuration).

Congratulations! The Apple Store Connect set up is ready 🎉

## RevenueCat configuration

1. Sign up for a new RevenueCat account [here](https://app.revenuecat.com/).
2. Navigate to the RevenueCat dashboard and [add a new project](https://app.revenuecat.com/overview)  from the dropdown in the top navigation menu called *Projects*.
3. Set *Fitness App Use Case* as **Project Name.**
4. From **Project Settings → Apps** in the left menu of the project dashboard, select **App Store**.

<figure><img src="/files/WHuJuMPyq8pyNhoAKUeT" alt=""><figcaption></figcaption></figure>

5. Set *Fitness App Use Case* as **App Name**.
6. Set your app’s bundle ID (the one in Apple Store Connect) as **App Bundle ID**.
7. Set the **App-Specific Shared Secret** and the **In-App Purchase Key** generated before.
8. Click **Save**.

### Products, Entitlements and Offerings

{% hint style="info" %}
Learn more about [how to configure products in RevenueCat](https://www.revenuecat.com/docs/entitlements).
{% endhint %}

1. In the **Products and pricing** menu of the left, click on **Products.**
2. Click on **+ New Product.**
3. Set *fa\_699\_1m* as **Identifier**, \*\*which the Product ID created before in Apple Store Connect.
4. Click **Create Product**.
5. Now go to **Entitlements** and click on **+ New**.

<figure><img src="/files/vrhhz6XPJVQKVRWaMr2E" alt=""><figcaption></figcaption></figure>

6. In **Identifier** set *full*.
7. In **Description** set **Full access to all videos and recipes.**
8. Click **Add**.
9. Now click on the *full* row to open the entitlement just created.
10. Click on **Attach**

<figure><img src="/files/aILzheXPhrVrZ8A4rHWi" alt=""><figcaption></figcaption></figure>

11. Click **Choose a product** and select *fa\_699\_1m - Fitness App Use Case*
12. Click **Add**.
13. Go to **Offerings** and click on **+ New.**
14. Set **default** as Identifier. This is critical, Bravo supports only this identifier.
15. Set any description and click **Add**.
16. Now click on the *default* row to open the offering just created.
17. Create a **+ New** package.
18. Select **Custom** Identifier and set it as *full.* Set **Description** as *Full access to all videos and recipes.*
19. Click on the table row just created corresponding with the *full* identifier.
20. Attach the product *fa\_699\_1m.*

RevenueCat set up is done! 🎉

### Review the design tags for In-app Purchase

Let’s open the Figma file and take a look on how it’s been bravorized. For example, the Home page has a container that we want to show only to premium users. We use the `[require:purchase:full]` tag for that. Note that full is the offering identifier we set in RevenueCat.

<figure><img src="/files/nZsCWJDhY4nAjzspYKej" alt=""><figcaption></figcaption></figure>

Now check out the Paywall page. We are using several tags:

* <mark style="color:red;">`[page:paywall]`</mark> for the main frame, to enable purchase actions.
* <mark style="color:red;">`[action:purchase:full]`</mark> to trigger the purchase action for the *full* offering we created in RevenueCat.
* <mark style="color:red;">`[price:full]`</mark> and <mark style="color:red;">`{price}`</mark> to show the price of the *full* offering in the user’s currency.

<figure><img src="/files/uwAZn34X5KMJeSCwPBP1" alt=""><figcaption></figcaption></figure>

Feel free to explore the design to learn more. For example, Upgrade buttons have the tag <mark style="color:red;">`[require:purchase:none]`</mark> to be visible only to free users.

{% hint style="info" %}
If you want to learn all you can do with Bravo and RevenueCat’s integration, check out the [In-app purchase documentation](https://docs.bravostudio.app/integrations/in-app-purchases-and-subscriptions-revenuecat).
{% endhint %}

## Enable RevenueCat in Bravo

The final step is to connect your Bravo app with RevenueCat.

1. Go to RevenueCat and copy the **API Key.**

<figure><img src="/files/NwLdSEz1ljl2qHV78fHp" alt=""><figcaption></figcaption></figure>

2. In Bravo Studio, go to your app → Integrations.

<figure><img src="/files/BPTVyJoiqleMex4g7hOb" alt=""><figcaption></figcaption></figure>

3. In **Payments**, enable **RevenueCat**.
4. Paste the key in **Apple (iOS) API Key.**
5. Click **Save**.

And we are done! 🎉

## TestFlight

In order to test In-app purchase on iOS, we need to use TestFlight. TestFlight is a platform developed by Apple that allows developers to distribute and test pre-release versions of their apps to a limited group of external testers before releasing them to the general public. It also allows to receive feedback from the group of testers.

#### Generate the IPA

1. In Bravo Studio, go to **your app** → **Publish** → **iOS**.
2. Fill the **Bundle ID** and **certificates** generated at the beginning of the tutorial.
3. Click on **Get IPA**.

In 15-20min you'll receive your IPA ready to be uploaded to Apple Store Connect.

{% hint style="info" %}
Remember that for each IPA you generate, the Build Number on the Bravo publication form needs to be higher than the previous one.
{% endhint %}

#### **Upload the app via Transporter**

1. Download the [Transporter app here](https://apps.apple.com/es/app/transporter/id1450874784?l=en\&mt=12) (available on the Mac App Store).
2. **Open Transporter** from your computer, enter your Apple credentials and **upload the .ipa file**
3. Click **Deliver.**

It may take some time for the package to appear in App Store Connect (can be minutes or up to an hour). You can check the status in the Activity section on the App Store Connect page.

*If you get an alert with the message that some tools are missing and you need Xcode, you will need to install* [*Xcode*](https://developer.apple.com/xcode/) *from the Mac App Store.*

#### **Add test users**

1. In **App Store Connect** click **Users and Access** at the top.
2. Click the **+** button
3. Fill the **New User** form. You can add yourself here. Make sure you check the app(s) you want them to have access to.
4. Click **Invite**.

The user will need to open the email and click on **Accept invitation**.

#### **Add testers to Internal Testing**

Users added to this group can access the app without needing Apple to do any review process. It's the quickest way to test your app with a bunch of users (up to 10.000).

1. In **App Store Connect**, go to **Apps** and **click the app** you want to add testers to.
2. At the top tab menu, click **Testflight**,
3. In **Internal testing**, click the **+** button.
4. In the **Create New Internal Group** modal window, enter a **name**. For example, "Testers" and click **Create**.
5. A new section will appear named as the group created. click the **+** button right after the title.
6. In the **Add Testers to the Group** modal window, **select** the testers and click **Add**.

The users will need to click on the **View in TestFlight** button from the email they received to see the app in TestFlight. Then accept and install the app.

{% hint style="info" %}
Let us know if you have any questions in the [Bravo community](https://community.bravostudio.app/)!
{% endhint %}


# Foodgram: Social content sharing

A social app for food lovers! This app has a feed of food photos and captions, the ability to create new posts and share existing, and comment on each post.

![](/files/-MeeNiMpzwuXuVpT_3hT)

## ✨ Features

* Feed (list of posts)
* Share image on other apps
* Add new post
* List of comments for each post
* Add new comment
* Horizontal scroll of "stories"
* Stories using Google Web Stories

## 💾 Resources

### **Design file: Figma**

**`Duplicate`** this Figma file into your account and import it into Bravo directly.\
**Includes:** containers, Bravo tags in layer names, prototype links for navigation

{% embed url="<https://www.figma.com/community/file/984134669464845417/Bravo-Sample%3A-Foodgram-app>" %}

###

### **Data source: Airtable**

Open the Airtable and click **`Copy Base`** to duplicate to your account.

**Database structure:**

1. Table **Posts**: Feed of photos & captions
2. Table **Comment**: comments of every photo

{% embed url="<https://airtable.com/shr58NxOPnenSVrN8>" %}

{% hint style="info" %}
**Tip:** Even though we use Airtable in this tutorial as our data source, you can use any  third-party backend tool you want to store the data.
{% endhint %}

## 🏗 How to build it

Follow the steps below or [watch](/get-started/help-and-tutorials/app-cases/bravo-app-kit-foodgram#webinar-walkthrough) the tutorial to learn how to build it!\
In this tutorial, we'll cover how to set up the connection between the Airtable and the app UI.

## Home feed

<mark style="color:blue;">`GET`</mark> `https://api.airtable.com/v0/TABLE_ID/Posts?view=VIEW_NAME`

Displays the photos and captions in a list.

#### Query Parameters

| Name | Type   | Description                                                 |
| ---- | ------ | ----------------------------------------------------------- |
| view | string | Display the photo feed list in the same order as the table. |

{% tabs %}
{% tab title="200 " %}

```
```

{% endtab %}
{% endtabs %}

Under **Received Data**, select the following 4 data paths in the screenshot below.

{% hint style="warning" %}
**Note:** Select **"All"** next to **.data.records\[]** to select **all** the records of the table, rather than a specific row.
{% endhint %}

![](/files/-Meed0Q4LQkg1j_QzCl_)

Change the **Name** of these two data paths. They will need to match the variables used later in the app page for creating a new post.

| Data Path                       | Name    |
| ------------------------------- | ------- |
| .data.records\[].fields.Caption | caption |
| .data.records\[].id             | postid  |

Go to the app project and select the home screen to open **data binding** mode. Bind the following UI elements with the respective data.

| UI element            | Data                           |
| --------------------- | ------------------------------ |
| Post list (container) | `Records[]`                    |
| image                 | `Records[]Fields.Image[0].Url` |
| caption               | `caption`                      |
| Send (share icon)     | `Records[]Fields.Image[0].Url` |

### **🎨 UI setup**

In the Figma file, the **Home screen** page includes these features:&#x20;

1. [Container: Top bar](/bravo-tags/containers/container-top-bar)
2. [Text: Flexo](/bravo-tags/components/component-flexible-text)&#x20;
3. [Container: Horizonal slider](/bravo-tags/containers/container-horizontal-slider)
4. [Open share dialog](/bravo-tags/mobile-actions)
5. [Refresh page](https://bravostudio.notion.site/7dae4abec25b441eac8044a73e000acc?v=04dc905954ff4103b3eb7279512a913b)
6. [Connect to API GET request for lists](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/set-up-an-api-get-request-for-list-page-airtable)

## Add new post

<mark style="color:green;">`POST`</mark> `https://api.airtable.com/v0/TABLE_ID/Posts`

Creates a new record of photo and caption in the database.

{% tabs %}
{% tab title="200 " %}

```
```

{% endtab %}
{% endtabs %}

Under the **Body** > **JSON** panel, input this:

```jsx
 {
   "records": [
     {
       "fields": {
         "Caption": "${caption}",
         "Image":[
                {
                   "url":"${url}"
                }
             ]
          }
       }
    ]
 }
```

Under the **Test Values** panel, input this:

| Key     | Value                                                                                     |
| ------- | ----------------------------------------------------------------------------------------- |
| caption | `test`                                                                                    |
| url     | `https://cdn.shopify.com/s/files/1/2994/0144/files/header_default.jpg` (or any image URL) |

Hit **`Send`** to send the request. \
Under **Received Data**, select the following 2 data paths in the screenshot below.

![](/files/-MeembAOVmssj34HfGFs)

Go to the app project and select the **New post** page to open **data binding** mode. Bind the following UI elements with the respective data.

| **UI element**   | Data      |
| ---------------- | --------- |
| \*\*image upload | `url`     |
| \*\*caption      | `caption` |

Under **Response Actions**, configure the following:

| Event        | Response action                     |
| ------------ | ----------------------------------- |
| ✅ On success | Go to page: Home screen             |
| ❌ On error   | Show alert: \<input your own alert> |

### **🎨 UI setup**

In the Figma file, the **New Post** page includes these features

1. [Form inputs](https://www.figma.com/community/file/981976861747536392)
2. [Page transitions](https://www.figma.com/community/file/981975323423403527)

Related article: [Connect to an API POST request ](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request)

## Comments list

<mark style="color:blue;">`GET`</mark> `https://api.airtable.com/v0/TABLE_ID/Comment?filterByFormula={Posts}='${caption}'`

Displays the list of comments associated with each post.

#### Query Parameters

| Name            | Type   | Description                                 |
| --------------- | ------ | ------------------------------------------- |
| filterByFormula | string | Filters data based on specific field values |

{% tabs %}
{% tab title="200 " %}

```




```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**filterByFormula explained**

* `{Posts}` = name of the table linked to this table
* `${caption}`= the input variable that determines which data from the **Comments** table is displayed.

In this case, we want to display the comments specific to each post - and the "**caption**" column is how we differentiate each post.
{% endhint %}

{% hint style="warning" %}
This input variable "**caption**" must match the "**Name**" (under "Selected Data") of the corresponding data path in the **Home feed** request - this way the two requests link together.
{% endhint %}

![Selected data from the GET: Home feed request.](/files/-Mef3fgJouKD4tNg1xn2)

As we have an input variable in the request URL, we need to input a test value in order to retrieve data. \
Under **Test Values** panel, input this:

| Key     | Value                                                    |
| ------- | -------------------------------------------------------- |
| caption | `Bread matters` (or any existing caption from the table) |

Hit **`Send`** to send the request. \
Under **Received Data**, select the following 2 data paths in the screenshot below.

{% hint style="warning" %}
**Note:** Select **"All"** next to **.data.records\[]** to select **all** the records of the table, rather than a specific row.
{% endhint %}

![](/files/-Mef4yVUvscmnPZOTFWt)

Go to the app project and select the **Comments** page to open **data binding** mode. Bind the following UI elements with the respective data.

| **UI element**           | Data                       |
| ------------------------ | -------------------------- |
| Comment list (container) | `Records[]`                |
| \*\*caption              | `Records[] Fields Comment` |

###

### **🎨 UI setup**

In the Figma file, the **Comments** page includes these features.

1. [Page transitions](https://www.figma.com/community/file/981975323423403527/Bravo-Sample%3A-Page-Transitions)
2. [Refresh page](https://bravostudio.notion.site/7dae4abec25b441eac8044a73e000acc?v=04dc905954ff4103b3eb7279512a913b)
3. [Text: Flexo](/bravo-tags/components/component-flexible-text)&#x20;
4. [Connect to any API: GET request for lists](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/set-up-an-api-get-request-for-list-page-airtable)

## Add new comment

<mark style="color:green;">`POST`</mark> `https://api.airtable.com/v0/TABLE_ID/Comment`

Creates a new record of comment in the database.

#### Path Parameters

| Name | Type   | Description |
| ---- | ------ | ----------- |
|      | string |             |

{% tabs %}
{% tab title="200 " %}

```
```

{% endtab %}
{% endtabs %}

Under the **Body** > **JSON** panel, input this:

```jsx
 {
   "records": [
     {
       "fields": {
         "Comment": "${comment}",
         "Posts": [
           "${postid}"
         ]
       }
     }
   ]
 }
```

Under the **Test Values** panel, input this:

| Key     | Value                                                                                      |
| ------- | ------------------------------------------------------------------------------------------ |
| comment | `test`                                                                                     |
| postid  | Get the `postid` from the Home screen request, it's an id string that starts with `rec...` |

Hit **`Send`** to send the request. \
Under **Received Data**, select the following data path in the screenshot below.

![](/files/-Mef8CrapXZA8Mw0WB_j)

Go to the app project and select the **Comments** page to open **data binding** mode. Bind the following UI elements with the respective data.

| **UI element**                | Data      |
| ----------------------------- | --------- |
| \*\*comment (input text area) | `comment` |

Under **Response Actions**, configure the following:

| Event        | Response action                     |
| ------------ | ----------------------------------- |
| ✅ On success | Go to page: Comments                |
| ❌ On error   | Show alert: \<input your own alert> |

###

### **🎨** UI setup

In the Figma file, the **New comment** page includes these features

1. [Form inputs](https://www.figma.com/community/file/981976861747536392)
2. [Fixed modal page](https://www.figma.com/community/file/967380255651810770)
3. [Connect to an API POST request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request)

## **📺 Webinar walkthrough**

{% embed url="<https://www.youtube.com/watch?v=O-AeEev34gk>" %}

Happy Bravorizing! 🎉


# Expedition journal: Write and share your adventures

This app shows a list of expeditions from an expedition team and a journal feed that tracks their journey. Here is how you can create it yourself.

{% embed url="<https://dl.airtable.com/.attachments/1fad6183eb9b2bd3f08687a873e46b80/5168d993/expedition-bravo.mp4>" %}

## :sparkles:Features

* [Lottie animation](/bravo-tags/components/component-lottie) as header
* Autoplay video as header background
* List & detail of expeditions from an Airtable spreadsheet
* Interactive Google Street Views
* Send journal entries via a Typeform
* List of journal entries from Airtable spreadsheet

## Resources

### :point\_right:**Design file: Figma**

Duplicate this Figma file into your account and import it into Bravo directly!

**Includes**

* Containers setup
* Bravo Tags in layer names
* Prototype links for navigation

{% embed url="<https://www.figma.com/community/file/1022541708893076578/Bravo-Sample%3A-Expedition-journal>" %}

###

### :point\_right:**Data source: Airtable**

Open the Airtable and click `Copy Base` to duplicate to your account.

**Includes**

* One table for the list of Expeditions
* One table for the list of journal entries

{% embed url="<https://airtable.com/shrg1zsgptawMTYNW>" %}

### :point\_right:**User input channel: Typeform**

This is the Typeform we embedded in the app to allow users to create journal entries to the Airtable. Connect it to your copy of the Airtable under the tab `Connect`

{% embed url="<https://codelesslabs.typeform.com/to/pJ4Q88>" %}

![](/files/-MhXaUcrW4O8UW7HuG2l)

{% hint style="success" %}
Even though we'll use Airtable here as our data source, you can use any other third-party tool you wish to store the data.
{% endhint %}

## :construction\_site: How to build it

Watch our webinar that takes you through building the Expedition app step-by-step 🙌

{% embed url="<https://www.youtube.com/watch?v=sk-ZniZiGAk&t=187s>" %}

Happy Bravorizing! 🎉


# My Subscriptions: Display data based on device ID

This app enables users to track all their subscriptions in one place and never miss cancelling an unwanted service before the free trial expires.

{% hint style="info" %}
**Find it in the app store** \
🍏 [Download](https://apps.apple.com/app/id1539067540) in App Store \
🤖 [Download](https://play.google.com/store/apps/details?id=app.bravostudio.A01EP5DVRG8DRN6VP0SFXJ3Y4YC) in Google Play
{% endhint %}

{% embed url="<https://dl.airtable.com/.attachments/8c70bfb147f61eadf73e472c5f296c8a/ce72dc26/subscription-bravo.mp4>" %}

## ✨ Features

* Home screen with [Lottie animation](/bravo-tags/components/component-lottie)
* Send subscriptions data via custom input form and submit action button
* List of subscriptions from an Airtable spreadsheet
* Use of device ID for multiuser functionality

## 💎 Resources

* **Design file: Figma**

  Duplicate this Figma file into your account and import it into Bravo directly!

  **Includes**

  * Containers setup
  * Bravo Tags in layer names
  * Prototype links for navigation

{% embed url="<https://www.figma.com/embed?embed_host=notion&url=https%3A%2F%2Fwww.figma.com%2Ffile%2F0mnWsQa6lMxpJHgXJrV9sk%2FMy-Subscriptions-tracker>" %}

* **Database: Airtable**

  Open the Airtable and click `Copy Base` to duplicate to your account.

  **Includes**

  * Table setup for the list of subscriptions and device id

{% embed url="<https://airtable.com/shrfwaDer1kxzWieU>" %}

{% hint style="success" %}
Even though we'll use Airtable here as our data source, you can use any other third-party tool you wish to store the data.
{% endhint %}

## 🏗 How to build it

Read or watch the step-by-step tutorial to learn how the Subscriptions app was created.

In this tutorial you will learn:

* How to create a POST, GET and DELETE API requests.
* Use the user device ID to add multiuser functionality to the app

**Written tutorial**

{% embed url="<https://pcodina.medium.com/too-much-saas-on-my-plate-501710e61cf2>" %}

**Video tutorial**

{% embed url="<https://www.youtube.com/watch?v=lMtKvRSMy9I>" %}

Happy Bravorizing! 👏


# My Notes: using user ID and email from Firebase

![](/files/-MhXc-CbwTNYJnEbyL3p)

In this tutorial, you'll learn how to set the [Bravo variables](/connect-api/request-url-variables#bravo-variables) `user.id` and `user.email`. The values of these variables are taken from an authentication provider, so the app must authenticate the users first in order to get these values.

To showcase this, we'll create a sample notes app. In this app, we'll set up an authentication flow and connect it to Firebase. Then, we'll use Airtable to store the user-related data. In order to show each user only their notes, we'll use the `user.id` value when storing a new note in the table. Finally, we'll set up a personalised message, where the user will see their own email as part of a greeting message.

{% hint style="info" %}
For this personalised message, another [Bravo variable](/connect-api/request-url-variables#bravo-variables) (`user.name`) could be used. Currently, this is not possible with Firebase, as it doesn't fill the value for this variable. When new authentication providers are integrated with Bravo, this variable will also have a value.
{% endhint %}

## ✨ Features

* User authentication with Firebase.
* Display a welcome message for the user with their email address.
* View, add, and remove notes, leveraging the user.id variable to show each user only their notes.

## 💎 Resources

* **Design file: Figma**

{% embed url="<https://www.figma.com/embed?embed_host=notion&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FLlISfOw3NWPdExqAcnWlg5%2FUser-Variables%3Fnode-id%3D0%253A1>" %}

* **Data source: Airtable**

  Open the Airtable and click `Copy Base` to duplicate to your account.

  **Includes**

  * Table setup for the notes, user id and user email.

{% embed url="<https://airtable.com/shrpihLWGUp69cQ2y>" %}

## 1️⃣ Set up authentication with Firebase

Once the design file has been imported into Bravo, follow [this tutorial](/integrations/user-authentication/app-login-firebase) in order to set up the authentication with **Firebase**.

## 2️⃣ Create the data collection and requests in the Data Library

Now, we'll create a Data Collection in the Data Library, to connect our API with Airtable, and to display the welcoming message with the `user.email` variable. We'll use the Airtable wizard when adding the API endpoint ~~tutorial~~ to speed things up - we'll need to provide the **Airtable base URL** and the **API Key** of our account.

Once the Data Collection has been created, we'll configure three API requests. These are detailed below.

{% hint style="info" %}
You can duplicate the requests generated by the Airtable tutorial in order to create new ones. This way, the Authentication value with the API key will be already copied in the request header.
{% endhint %}

### `GET` List Notes

In this request, we'll get the list of notes from Airtable. However, we don't get all the notes, but only the ones that are associated with a certain `user.id`. The value for this variable will be filled once the user is logged in, so each user will only be able to see their own notes.

In order to set up this request, follow these steps:

1. Set the following request URL

   ```jsx
    https://api.airtable.com/v0/**BASE_ID**/**TABLE_NAME**?filterByFormula={userid}='${user.id}'
   ```

   Note that the **BASE\_ID** and **TABLE\_NAME** values will be custom for your own Airtable base and table name. These are found in the request URL generated by the Airtable tutorial.
2. In the **Parameters** tab, set the parameter key `user.id` with the value `test_id` (this is the value we have in our Airtable base for the three sample notes). Then, hit `Send`. This will return the three sample notes.
3. In the **Received Data** tab, make sure all these data records below are selected. This will allow us to bind the data later in the screens.

![](/files/-MhXc-CitTWslHs2UkJS)

### `GET` Get User Email

This will be a special request to be able to display the `user.email` variable in the welcoming message. As Bravo binds the data that comes from an API, we first need to send the `user.email` variable to an API service once the user is logged in, then fetch it from that API to display it on the screen. There's a service called [httpbin](https://httpbin.org/) that allows you to create a request URL with a certain parameter, that will trigger a response containing that same parameter. This way, we can send the user.email variable to the httpbin service, and fetch it again using the same GET request.

In order to set up this request, follow these steps:

1\. Set the following request URL

```jsx
https://httpbin.org/get?name=${user.email}
```

This will send the `user.email` variable to the **httpbin** service as a query parameter, and get that value back in the response body (received data).

2\. In the Parameters tab, set the parameter `user.email` with the value `user_test` (just a sample value, you can use any value you wish). Then, hit `Send`. We need to do this in order to configure the request for later use in our app.

3\. Finally, in the **Received Data** tab, select the `.data.args.name` *\*\**&#x70;arameter. You'll see here the value you set as a parameter before sending the request. This will be the parameter that we'll bind to the home screen later, to display the welcome message with the user email.

![](/files/-MhXc-Cexg9gIIf7f3bM)

### `POST` Add Note

Finally, we'll set up a **POST** request to be able to add a note. In the request body, we'll add the note content and the `user.id` variables, respecting the structure that we created in Airtable.

In order to set up this request, follow these steps:

1\. Set the following request URL:

```jsx
 https://api.airtable.com/v0/**BASE_ID**/**TABLE_NAME**
```

2\. In the **Body** tab, select `JSON`, and copy the following JSON body. In this body, we defined the `noteContent` and `user.id` variables with the dollar sign and the brackets. The `noteContent` variable value will be fetched later from one of the screens, and the `user.id` will be automatically filled in by Bravo with the `user.id` value.

```jsx
 {
   "records": [
     {
       "fields": {
         "note": "${noteContent}",
         "userid": "${user.id}"
       }
     }
   ]
 }
```

{% hint style="warning" %}
It's very important to respect the naming that is set in Airtable. The "note" and "userid" key names are also the names of the colums in the Airtable base provided for this tutorial. If you change those names, you must change the key names in the JSON body as well. Otherwise, there will be an HTTP error when sending the request.
{% endhint %}

3\. Now, as we did for the previous requests, we need to set test values for the variables we defined for this request (`noteContent` and `user.id`). In the **Parameters** tab, set those test parameters to any value you wish.

![](/files/-MhXc-Cc2gyOt1SOH1AZ)

Then, hit `Send`. You should see the test parameters you have set both in the Airtable base and in the **Received Data** tab. We'll not need any of those values that we get in the response (recall that we have set a **List Notes** request to display all the notes), you can just leave it as it is.

![](/files/-MhXc-CdTRr0S41hJ5Fa)

## 3️⃣ Bind the screens to the data

Finally, we can bind the screens that we imported from Figma to the data by using the API requests we just set. We'll want to bind the **Home**, **Add note** and **Notes** pages with the **Get User Email**, **Add Note** and **List Notes** requests, respectively.

### Home screen

In this screen, we want to fetch the `user.email` variable to display a welcome message. We'll use the API request we specifically created for this, with the **httpbin** service.

1. In your Bravo project, click on the **Home** app page to open the **Data Binding** mode. Then, select the **Data Collection** we created (the group of API requests), and select the **Get User Email** request.
2. Select the `User` text element in the `greeting` frame, and bind it to the **variable containing the user email**. The name of this variable is set in the **Selected Data** tab of the Data Library, go there and check it out if you're not sure of which variable you should select.

### Notes screen

This screen will be the one listing all the user notes. Therefore, we must bind it to the **List Notes** request we set up before.

1. In your Bravo project, click on the **Notes** app page to open Data Binding mode. Then, select the Data Collection we created, and select the **List Notes** request.
2. Bind the **Notes container** to the `Records` value on the right pane, and the **Note text element** inside to the **variable representing the note content** (remember that this is set in the **Selected Data** tab of the Data Library).

![](/files/-MhXc-Cf_-xFabXCvVq6)

{% hint style="info" %}
If you preview on Bravo Vision now, this page will appear empty because you have not yet added any notes under your user ID. Add an empty page state to visually inform your users.
{% endhint %}

### Add note screen

Finally, we'll bind the **Add note screen** to the **Add Note** **request**, so that the user can add new notes.

1. In your Bravo project, click on the **Add note** app page. Then, select the Data Collection we created, and select the **Add Note** request.
2. Select the `Add note...` text form field inside of the main container, and bind it to the `noteContent` variable we defined in the JSON body of the Add Note request.
3. Finally, in the **Response Actions** pane, under On Success, select `Go To Page`, and choose the **Notes** page. This way, the app will navigate to the Notes screen after the user submits a new note. You can also set up a message to display in case an error occurs when sending the note.

![](/files/-MhXc-ChL1GrmuGl8HNY)

That's it! 🥳


# My Store: Sell physical products with Bravo and Stripe

In this tutorial, we'll show how to create an e-commerce app to sell physical products, using our [Payment with Stripe](/integrations/payment-with-stripe) feature. We'll retrieve the products data from **Airtable**, and create a personalised checkout page for each product.

In order to implement this app case, you'll need to set up a [Stripe](https://stripe.com/es) account, and have an **Bravo Solo plan**.

![](/files/-Mj3_bBphNQWuqMM6Zvq)

{% hint style="info" %}
If you are new to Bravo, we recommend you check out [this page](broken://pages/-Mflj2uo5W_jthsMwnSm) before following this tutorial, to get some knowledge on how to use the Bravo **Data Library** and **Data Binding**.
{% endhint %}

## 💎 Resources <a href="#resources" id="resources"></a>

**Design file: Figma**

This Figma file is *bravorized* (i.e. ready to be imported into Bravo). If you want to customize it, duplicate it in Figma and make your changes, but make sure to **not remove** Bravo elements such as containers and tags.

The Figma file includes two screens: one to show all the available products on a list, and another one to buy a product from the list, containing a checkout form. In this form, the user will introduce the following information:

* Full name.
* Email address.
* Phone number (the user will need to add the +XXX specific [country code](https://www.countrycode.org/)).
* Credit card details.
* Additional comments.

Our Figma file includes all the tags needed to implement the Stripe Payment feature, and to collect the data indicated above in your Stripe account. In this case, we're using **hidden input** **fields** to be able to bind the price of each product with the data stored in Airtable. You can check out all the information regarding the payment-related Bravo Tags [here](/integrations/payment-with-stripe).

{% @figma/embed fileId="VrG3LALLpvxnnkyISR6fJv" nodeId="9500:0" url="<https://www.figma.com/file/VrG3LALLpvxnnkyISR6fJv?node-id=9500:0>" %}

**Data source: Airtable**

Open the Airtable and click `Copy Base` to duplicate to your account.

**Includes**

* A table with three physical products, containing a product name, price, and picture.

{% embed url="<https://airtable.com/shrnTCTCNZvuJoYLO>" %}

## 🚧 Creating the API requests in the Data Library

First, we'll create the API requests needed to connect our Airtable database to Bravo. In the Data Library, click on `Create New Collection` and use the Airtable wizard. This will generate two API requests (list and detail) for our product table.

### &#x20;   1. **`List`** **request**

This request will list all the products from the table. We'll use it later to display a list of the available products on the home screen.

To select the necessary data, hit **`Send`** and make sure that, at least, the following items are selected:

![](/files/-Mj3cLWw64BWEX6fUk4P)

### &#x20;   2. **`Detail`** **request**

This request will list one item of the table, based on the item ID passed as a query string parameter in the URL. If you used the Airtable wizard to setup the requests, the URL for the "detail" request will look like this:

```
https://api.airtable.com/v0/BASE_ID/TABLE_NAME/${ID}
```

The ID parameter is introduced as a Bravo Variable in the URL, and needs to have the same name and spelling as the ID value on the "**Selected Data**" panel of the **"List" request** - this way, Bravo will know to bind the two requests.

Similar to what we did with the **"List" request**, we need to select the data items that will later be used when binding the UI elements. In order to do that, we need to perform a request by clicking `Send`. As the URL contains a Bravo variable, we need to specify a temporary value for it, so the request retrieves a real item from the table.

Go to the **"List" request**, and on the `Received Data` tab, copy the ID value of one list element (the string to the left of the `.data.records[].id` path).

In the **"Detail" request**, go to the **Parameters** tab, set `ID` as the **key** (same spelling as the Bravo variable on the URL), and the copied ID string as the **value**.

Then, hit `Send` and make sure that, at least, the following items are selected:

![](/files/-Mj3cjvifSZGKkTZdVZy)

As indicated before, you can change the name of the data items on the `Selected Data` panel.

## 📲 Binding the data to the app UI

After setting up the API requests and selecting the data items in the Data Library, it's time to bind the app screens to the data!

We have two screens in our design: one to list all the items on our table, and another one to display a custom checkout page for each of the items. In this screen, the app users will introduce their personal and credit card data to purchase a physical product.

### **`Product List` screen**

This screen will display the list of products available in our e-commerce app. We'll bind the UI elements to the data as follows:

![](/files/-Mj3eCdBqmV_QaFQ5Cb_)

### **`Product Detail` screen**

On this screen, besides the product name and image, we'll bind the **price** (stored in our Airtable) to the **hidden input field** defined in the design file. This hidden input field will be linked to the product price, so when submitting the payment form, the amount indicated there will be charged to the user.

Bind the UI elements to the data as follows:

![](/files/-Mj3eLfw1KZPKKrvkirF)

Finally, on the `Response Actions` panel, select `Go to page` and `Product List`, so the user is redirected here after the purchase. You can also create a confirmation page to redirect the user.

## 💰 Connect your Stripe account

Finally, you'll need to connect your Stripe account on the "**Settings**" panel inside your Bravo project. Go to the `Stripe` tab, click on `Connect`, and then log in to your Stripe account.

![](/files/-Mj3eeMsJgCxvLvs0hK2)

Congrats! You can now test your e-commerce app in Bravo Vision, and send real payments to your Stripe account.

Happy Bravorizing! 🥳


# Learn with videos

Check out these videos to get a sense of what Bravo can do!

## :bulb:Learn to Bravo

{% tabs %}
{% tab title="Bravo Tips" %}
{% embed url="<https://www.youtube.com/playlist?list=PLzg-UiRu-a_YTj5_eTVuR1uNmAFHKBuew>" %}

{% embed url="<https://www.youtube.com/watch?v=fyiKuxDW_dQ>" %}

{% embed url="<https://www.youtube.com/watch?v=fygNOgav4-w>" %}

{% embed url="<https://www.youtube.com/watch?v=I01hwRmK4DE>" %}

{% embed url="<https://www.youtube.com/watch?v=62IYPw4aIwU>" %}

{% embed url="<https://www.youtube.com/watch?v=NPpgCaYZ0TE>" %}

{% embed url="<https://www.youtube.com/watch?v=u4OpyDkWvmw>" %}

{% embed url="<https://www.youtube.com/watch?v=VZBFxIO-D5U>" %}

{% embed url="<https://www.youtube.com/watch?v=uU2elN3upMo>" %}

{% embed url="<https://www.youtube.com/watch?v=0RSPRbsKrBk>" %} <br>
{% endembed %}
{% endtab %}

{% tab title="Tutorials" %}
{% embed url="<https://www.youtube.com/watch?v=6wuJVEUdT44>" %}

{% embed url="<https://www.youtube.com/watch?t=124s&v=R8z9mx8RgrE>" %}

{% embed url="<https://www.youtube.com/watch?t=2679s&v=f2nXazGzmEU>" %}

{% embed url="<https://www.youtube.com/watch?v=VM5ipS1uLvM>" %}

{% embed url="<https://www.youtube.com/watch?v=SPKdCa57Lno>" %}

{% embed url="<https://www.youtube.com/watch?v=Ozs25I-oewQ>" %}

{% embed url="<https://www.youtube.com/watch?v=vixjPv5YFdw>" %}

{% embed url="<https://www.youtube.com/watch?t=2468s&v=v1BYft7_L6c>" %}

{% embed url="<https://www.youtube.com/watch?v=Kw6N1NIrjrI>" %}
{% endtab %}

{% tab title="Webinars" %}
{% embed url="<https://www.youtube.com/watch?v=sk-ZniZiGAk>" %}

{% embed url="<https://www.youtube.com/watch?v=lMtKvRSMy9I>" %}
{% endtab %}

{% tab title="Build it with Jonas" %}
{% embed url="<https://www.youtube.com/playlist?list=PLzg-UiRu-a_ZgsQEz7x-sdYpBAS6MoJZf>" %}
{% endtab %}
{% endtabs %}

## :nerd: Bravo Crash Course

{% tabs %}
{% tab title="Beginner" %}
{% embed url="<https://www.youtube.com/playlist?list=PLzg-UiRu-a_aMrSlzRjuzCEE8CUv_4jG>\_" %}
{% endtab %}

{% tab title="Ready" %}
{% embed url="<https://www.youtube.com/playlist?list=PLzg-UiRu-a_afryVP8Z7AMaPW6jn-vNDE>" %}
{% endtab %}

{% tab title="Accelerate" %}
{% embed url="<https://www.youtube.com/playlist?list=PLzg-UiRu-a_Y5TgHkByRcPX8PkqvAcDMI>" %}
{% endtab %}

{% tab title="Victory" %}
Coming soon.
{% endtab %}

{% tab title="Expert" %}
Coming soon.
{% endtab %}
{% endtabs %}

## :star\_struck:Videos featuring Bravo

{% tabs %}
{% tab title="What is Bravo?" %}
{% embed url="<https://www.youtube.com/watch?v=t15BZZ1giGo>" %}

{% embed url="<https://www.youtube.com/watch?v=8IT-hfjGTKk>" %}

{% embed url="<https://www.youtube.com/watch?v=mlkmd49Uhyo>" %}

{% embed url="<https://www.youtube.com/watch?v=nOPaOWcAO38>" %}
{% endtab %}

{% tab title="Build an app with Jesse Showalter" %}
{% embed url="<https://youtu.be/XhimuVI8GQs>" %}

{% embed url="<https://www.youtube.com/watch?v=GX73V6I14iQ>" %}

{% embed url="<https://youtu.be/6T0IpS5gNQg>" %}

{% embed url="<https://www.youtube.com/watch?v=ajfIH9HhoyU>" %}

{% embed url="<https://www.youtube.com/watch?v=gpQ5_cUc_B8&list=PLzg-UiRu-a_bobp_RwK-ydb9MQyI5zaHS&index=5>" %}
{% endtab %}

{% tab title="Bravo + Xano: Build a photo sharing app" %}
{% embed url="<https://www.youtube.com/watch?v=fQ-pqFK2qkc>" %}
{% endtab %}
{% endtabs %}


# Learn with articles

Check out these articles to learn step-by-step how to Bravo

## :books: Bravo article collection

{% tabs %}
{% tab title="Build an app" %}
{% embed url="<https://medium.com/bravostudio-app/how-bravo-studio-delivers-complex-native-and-beautiful-apps-in-a-flexible-way-a00d3be60266>" %}

{% embed url="<https://medium.com/geekculture/creating-native-mobile-apps-from-bubble-applications-using-bravo-studio-a75c4c592d5d>" %}

{% embed url="<https://tobyo.medium.com/mobile-frontendless-photo-sharing-app-using-figma-and-backendless-c950cf5207c8?source=user_profile---------3---------------------------->" %}

{% embed url="<https://tobyo.medium.com/instagram-clone-in-30-minutes-using-bravo-studio-and-xano-1b09110c1a0a>" %}

{% embed url="<https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/>" %}

{% embed url="<https://medium.com/bravostudio-app/how-to-build-skeleton-loading-screens-in-bravo-studio-7e2240cb2b82>" %}

{% embed url="<https://medium.com/geekculture/tutorial-to-build-a-native-typeform-responses-app-using-bravo-studio-in-15-minutes-nocode-1b6ab62517b3>" %}

{% embed url="<https://medium.com/bravostudio-app/comparing-the-performance-and-features-of-nocode-backends-like-airtable-backendless-bubble-35d65d043f12>" %}

{% embed url="<https://www.industrial-devops.org/mobile-app-fuer-das-smart-home-mit-no-code-entwickeln/>" %}

{% embed url="<https://tobyo.medium.com/whats-love-got-todo-with-it-74c9a3da53ce>" %}

{% embed url="<https://tobyo.medium.com/were-walking-in-the-air-table-33bc6c20f8f0>" %}
{% endtab %}

{% tab title="Case studies" %}
{% embed url="<https://medium.com/bravostudio-app/dont-worry-be-api-when-designing-1c79af8c7461>" %}

{% embed url="<https://medium.com/@j.vdeyl/publishing-an-app-to-the-app-store-without-coding-bravo-studio-15118c12ca1a>" %}

{% embed url="<https://medium.com/@patrick.burkert/how-we-launched-an-app-idea-to-market-in-less-than-one-week-with-bravo-6e5f07ecf39f>" %}
{% endtab %}
{% endtabs %}


# Browse by app feature

Learn how to implement specific functionalities inside your apps

## Functionalities

### **👏 Beginner**&#x20;

**Content & Media**

* [ ] [Content feed (list page)](/data-binding/display-data-in-your-app/data-biding-bind-data-to-ui-for-a-list-page)
* [ ] [Add content (form page)](/bravo-tags/form-and-input-fields/data-biding-send-form-input-to-a-database)
* [ ] [Delete content](/data-binding/delete-data-from-your-app)
* [ ] [Search bar (filters items from a list by text content)](/bravo-tags/mobile-actions/component-search-and-filter)
* [ ] [Nested list pages (list page followed by a list page)](/connect-api/browse-by-backend/airtable/airtable-nested-lists-with-airtable-list-list-detail-page)
* [ ] [Flexible text box for dynamic content](/bravo-tags/components/component-flexible-text)

**Mobile actions**

* [ ] [Scan QR code](/bravo-tags/mobile-actions/scan-qr-code)
* [ ] [Zoomable images](/bravo-tags/components/zoomable-image)
* [ ] [Open web page in-app](/bravo-tags/components/component-webview)
* [ ] [Play MP3 audio](/bravo-tags/mobile-actions/action-play-audio)

**Onboarding**

* [ ] [Intro pages (before login)](/bravo-tags/intro-and-onboarding/page-intro)

### **💪 Advanced**

**States**

* [ ] [Empty state page (for no results returned from API)](broken://pages/aBeNObDzfcPA39O9WWh6)
* [ ] [Error state page (for error returned from API)](broken://pages/HndzqhDRUgvq2hjcmc94)

**Content interactivity**

* [ ] [Save / bookmark / favorite action](/connect-api/browse-by-backend/xano/xano-create-a-bookmark-functionality-with-remote-actions-and-device-id)
* [ ] [Like button](/bravo-tags/components/stateful-component-like-button)&#x20;

**Search**

* [ ] [Perform a backend search with input fields](/get-started/help-and-tutorials/browse-by-app-feature/backend-search-with-airtable)

**Location-related**

* [ ] [Map with location pins](/bravo-tags/map-with-markers)
* [ ] [Display device location](/bravo-tags/mobile-actions/share-location)

**Login & user profile**

* [ ] [Login with email & password](https://docs.bravostudio.app/integrations/user-authentication/app-login-firebase)
* [ ] [Login with phone number & OTP (one time password)](https://docs.bravostudio.app/integrations/user-authentication/app-login-firebase#phone-login-setup)
* [ ] [Login with Facebook, Google, Apple (OAuth 2.0)](/integrations/user-authentication/oauth2/example-using-social-logins-to-authenticate-users)
* [ ] [Login to Spotify account](/integrations/user-authentication/oauth2/example-connecting-to-spotify-api)
* [ ] [Login with AWS Cognito](/integrations/user-authentication/oauth2/example-using-aws-cognito-to-authenticate-users)
* [ ] [Post-login page (onboarding pages)](/bravo-tags/intro-and-onboarding/post-login-page-onboarding)

## Effects

### ✨ Beginner

* [ ] [Custom loading animation with Lottiefiles](/bravo-tags/loading-experience/state-custom-loading-page)
* [ ] [Fixed header](/bravo-tags/containers/container-top-bar)
* [ ] [Horizontal slider scroll](/bravo-tags/containers/container-horizontal-slider)
* [ ] [Background video](/bravo-tags/components/component-autoplay-video)
* [ ] [Lottie animation](/bravo-tags/components/component-lottie)
* [ ] [GIF](/bravo-tags/components/component-gif)

### 💎 Advanced

* [ ] [Floating (sticky) action button](/bravo-tags/containers/layer-sticky-element)
* [ ] [Skeleton loader](/get-started/help-and-tutorials/browse-by-app-feature/skeleton-loader)
* [ ] [Maintain aspect ratio on all device](/bravo-tags/containers/aspect-ratio-relative-to-screen)
* [ ] [States on buttons & icons (active, pressed)](/bravo-tags/components/component-states)


# Save or "bookmark" a page

In some app cases, you'll want to display a list of items that users can bookmark or "like", so they have easier access to them later in a separate screen. This can be implemented with the [toggle component](/bravo-tags/components/stateful-component-like-button), together with some backend setup to implement the needed logic.

In order to implement this feature, follow the documentation below.

{% content-ref url="/pages/x5AXWZWsioMirUf3I15M" %}
[Stateful component (like button)](/bravo-tags/components/stateful-component-like-button)
{% endcontent-ref %}


# Backend search with Airtable

Performing a backend search can be very useful when trying to filter items according to one or more properties, specially when there's a big number of items.&#x20;

The video below describes how to perform a text search over an Airtable base, using a form in our app (text input + submit button).&#x20;

This could be expanded to other types of search, or to other backends, applying the same idea. The backend should be responsible of applying the necessary filters to return the corresponding items, depending on the user input.

{% embed url="<https://www.youtube.com/watch?t=6s&v=dXSgk1cyB70>" %}

For smaller lists and searching in the same screen, consider using the Search & Filter functionality:

{% content-ref url="/pages/-MhxbA\_PKkuV6MhfQWK2" %}
[Search & filter](/bravo-tags/mobile-actions/component-search-and-filter)
{% endcontent-ref %}


# Backend search with Xano

Performing a backend search can be very useful when trying to filter items according to one or more properties, specially when there's a big number of items.&#x20;

The video below describes how to perform a text search over a Xano table, using a form in our app (text input + submit button).&#x20;

This could be expanded to other types of search, or to other backends, applying the same idea. The backend should be responsible of applying the necessary filters to return the corresponding items, depending on the user input.&#x20;

### Design

<figure><img src="/files/WI1evwflqkBHihboZ9fg" alt=""><figcaption><p>Figma Example</p></figcaption></figure>

### Database in Xano

<figure><img src="/files/6N3EiDG8kSWhQ9IsDaLj" alt=""><figcaption><p>Fitness_recipe List Table</p></figcaption></figure>

### How to set up the Backend Search with Xano

Based on the [Fuzzy Search tutorial in Xano](https://www.youtube.com/watch?v=5_XkvyAX2C0).

{% embed url="<https://www.loom.com/share/d59dc00dc8f0407f98332415de102ffd?sid=ce90b1e9-69ca-4a53-98cf-3cb591415604>" %}

For smaller lists and searching in the same screen, consider using the Search & Filter functionality:

{% content-ref url="/pages/-MhxbA\_PKkuV6MhfQWK2" %}
[Search & filter](/bravo-tags/mobile-actions/component-search-and-filter)
{% endcontent-ref %}


# Nested lists (list within a list)

In some app cases, you'll want to navigate inside lists that are nested with each other. For instance, an app screen displaying a list of countries, another screen displaying cities inside a specific country, and finally a detail page showing information about a city.&#x20;

{% content-ref url="/pages/-Mfm1p4rW-2Qj-Lhaqi6" %}
[Nested lists (list > list > detail page) with Airtable](/connect-api/browse-by-backend/airtable/airtable-nested-lists-with-airtable-list-list-detail-page)
{% endcontent-ref %}

{% content-ref url="/pages/-Mfm3hksRf0vi1xtnTt7" %}
[Nested lists (list > list > detail page) with Xano](/connect-api/browse-by-backend/xano/xano-build-nested-lists)
{% endcontent-ref %}

##


# Create and edit user profile (Firebase + Airtable)

Learn how to allow users to create and edit user profiles, using Firebase for authentication and Airtable as the app backend.

In this tutorial, we’ll use Firebase email-based authentication combined with post-login to create a user onboarding flow, where new users can add more information about them. Also, we’ll create a page where users can edit their profile information. We’ll use Airtable as our backend to store the user information.

You can follow this tutorial step by step to create the same use case we'll be showing, and you can also adapt it to your specific app.

## 🎨 Design file

In this tutorial, we’ll use the Figma file below, with all the tags required to implement the [Firebase email-based authentication](/integrations/user-authentication/app-login-firebase) and [post-login flow](/bravo-tags/intro-and-onboarding/post-login-page-onboarding). Feel free to duplicate it and customize it as you need, before importing it into Bravo to create a new app project. You can also import it as it is.

{% embed url="<https://www.figma.com/community/file/1139917619983944012>" %}

## 👥 Authentication setup (Firebase)

Before continuing with the tutorial, you’ll need to set up a Firebase project in order to use Firebase authentication. Follow [this guide](/integrations/user-authentication/app-login-firebase/email-password-login-firebase) to do that. You can skip the design section, since the necessary tags are already included in the design file we provided above.

As you’ll see, you’ll need to generate some files in Firebase and upload them to your Bravo app settings to enable Firebase authentication.

## 💾 Backend setup (Airtable)

We'll use [Airtable](https://www.airtable.com/) to store the user profile information. In case you haven't done that already, create a free account and a base to store the user information.

In this example, we created the following fields, which match the input fields for the forms where users can create and edit the profile information:

* Name (text field)
* Surname (text field)
* Age (numeric field)
* UserID (text field)
* Last Modified. We created this field to be able to sort the table by edit date and time. This is important in order to retrieve the correct user profile data later on.

You can duplicate the base below to get started:

```
https://airtable.com/appVmNCG1OLuQMiOe/shr1eL0nU7mEzguY3
```

## ⚙️ API collection setup

Once we have our design and backend ready, it's time to create all the API requests that are needed to connect our app and the backend. In case you haven't done so, import the [Bravorized](/set-up-design/setting-up-your-design-file) example design file (or your own file), with all the necessary Bravo tags, to create a new app project.

After creating your app project, create a new [API collection](/connect-api/set-up-api-requests/api-wizard-importer). You can use the Airtable wizard with your Airtable base, which will already generate a few API requests for you.&#x20;

{% hint style="info" %}
In case you use the wizard, note that you'll need to edit these requests and create new ones to match the ones we'll describe below. You can duplicate the ones created with the wizard, which will already contain the Airtable base URL and API key.
{% endhint %}

### Get User Profile - <mark style="color:green;">`GET`</mark>

We'll use this request to obtain the user profile data, by providing a [user ID](/connect-api/request-url-variables#built-in-variables), filtering the Airtable base by this user ID (using [filterByFormula](https://support.airtable.com/hc/en-us/articles/223247187-How-to-sort-filter-or-retrieve-ordered-records-in-the-API)), and returning the data associated to that user. This is necessary in order to load values for the input fields in the page to edit the user profile, and allow the user to change them.

It's important that we also include the [Airtable view name](https://support.airtable.com/hc/en-us/articles/202624989-Views-overview), since this will keep the data records sorted in the same way as in the table (by latest modified). This is done to make the data management more robust: in case a user, for some reason, submits profile information under the same user ID more than once, we'll only use the latest data.

Replace `<BASE_ID>`, `<TABLE_NAME>` and `<VIEW_NAME>` with the corresponding values for your table.&#x20;

```
https://api.airtable.com/v0/<BASE_ID>/<TABLE_NAME>?filterByFormula={userID}=%22${user.id}%22&view=<VIEW_NAME>
```

To test the request, you'll need to use a test value for the ${user.id} variable. You can fill in a dummy value in your Airtable base, and reuse this value in the API request:

![](/files/RbWYQGHgZSkKplZjPd3j)

![](/files/veqfZff0JfX42lwsYTlJ)

After testing the request successfully, select all the items related to the user profile. In this case, we don't want to create a list, but rather get the values for one specific user, which is one row in the Airtable base. Therefore, **it's very important that you select the 0 index in the dropdown for the .data.records path**. These data items will correspond with the latest profile information for the specific user ID we provided in the request - in case there's more than one row for that user ID, we'll always use the data for the "latest modified" one.

![](/files/143MkpLLBzeRrlIURqBr)

Finally, go to the "Output Variables" tab and set the following names for the data items you've selected. **It's very important that you set the name indicated below for the profile ID**, since we'll be using the same name in later steps and any misspelling will make the feature not to work properly.

![](/files/BBC0ifVwjNhdv41Bf51B)

### Post User Profile - <mark style="color:blue;">`POST`</mark>

We'll use this request for the form where users can create a profile in the app onboarding. To do that, we'll use the following request URL and JSON body:

In the request URL, replace `<BASE_ID>` and `<TABLE_NAME>` with the corresponding values for your table.

```
https://api.airtable.com/v0/<BASE_ID>/<TABLE_NAME>
```

JSON body:

```
{
  "records": [
    {
      "fields": {
        "Name": "${name}",
        "Surname": "${surname}",
        "Age": ${age},
        "UserID": "${user.id}"
      }
    }
  ]
}
```

You can use some test values here as well to test the request. Since this is a POST request that we'll use to submit the user onboarding form, we don't need to select any data for binding - we'll only use the request to send data to Airtable.

### Edit User Profile - `PATCH`

Finally, we'll need a PATCH request to allow a user edit the profile information they submitted in the onboarding (for instance, change the name or the age). This PATCH request will target the specific row we obtained in the Get User Profile request, and change it with the new information the user submitted. We'll use the URL and JSON body indicated below for the request.

In the request URL, replace `<BASE_ID>` and `<TABLE_NAME>` with the corresponding values for your table.

```
https://api.airtable.com/v0/<BASE_ID>/<TABLE_NAME>
```

JSON body:

```
{
  "records": [
    {
      "id": "${profile_id}",
      "fields": {
        "Name": "${name}",
        "Surname": "${surname}",
        "Age": ${age}
      }
    }
  ]
}
```

<figure><img src="/files/bykfllyK5lG9iV0hmVgw" alt=""><figcaption></figcaption></figure>

Note that we're using here a variable called `${profile_id}` as the record ID value. As you remember, we indicated the same name for the data item that returns the record ID in the [Get User Profile](#get-user-profile-get) request. These two names must match for the feature to work properly, since this is how Bravo knows which ID value to pass to the PATCH request, so it targets the correct table record.

![](/files/BBC0ifVwjNhdv41Bf51B)

Now, you can use some test values to test this PATCH request. Make sure you indicate a valid profile\_id, you can get one from the Get User Profile request as shown below:

![](/files/3nZf2xszm9pGJy9jpkLB)

<figure><img src="/files/7AiKIHuym3M076GGKYED" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Remember to set the headers of all the requests with the same Authorization!
{% endhint %}

## ⚒️ Data Binding setup

Once the API requests are created, it's time to bind them to the necessary app screens. We'll need to bind two screens:&#x20;

* The page where new users create a new profile in the onboarding&#x20;
* The page where existing users can edit the profile information they submitted in the onboarding.

### "user-profile" page

This is the screen created with the post-login functionality, where new users who register will navigate after registering with their email and password. The screen is called "user-profile" in our design example.

We'll bind the variables in the [Post User Profile](#post-user-profile-post) request to the form input fields in this screen, so a new record is created in Airtable with the new user profile. As you can see in the screenshot below, we'll bind the "Input Destination" property of the input fields to the corresponding variable.

![](/files/VXd8wO0d3HxHyWMYVecd)

<figure><img src="/files/UJXnTYZRSbEKkDxRqKZo" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/BbGIUAcyfZoVenZJvn3D" alt=""><figcaption></figcaption></figure>

Finally, we'll make the users navigate to the "success" screen in case they created the user profile successfully, and show an error alert in case the API request was unsuccessful.

![](/files/4qyS8GQ7JdeSABdiOSA4)

### "edit-profile" page

In this page, we'll allow existing users to change their profile information.&#x20;

We'll bind the "Value" property of the input fields to the [Get user profile](#get-user-profile-get) request. This way, a user goes to this screen, they'll see the current profile data populate in the input fields. Then, they'll be able to edit as many fields as they wish.

Secondly, we'll bind the "Input Destination" property of the fields to the Edit user profile request. This way, when they submit the form, the new profile information will be sent to Airtable, and the corresponding table record will be updated with the information provided in the form. In case a user doesn't change all the fields, the information obtained with the "Value" property binding will be sent along - therefore, those data fields won't change.

![](/files/bgMrF30eWgmDRAVBmH14)

<figure><img src="/files/1zvctEMErGkr82ZvHpoD" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8btPnNmf59HwRxU9unuW" alt=""><figcaption></figcaption></figure>

Finally, we'll also set up an alert, so the user knows that the profile was edited successfully, or that an error happened.

<figure><img src="/files/CrIhBysGpeRpJgiyRQIh" alt=""><figcaption></figcaption></figure>

## 📲 Test your app in [Bravo Vision](/good-to-know/faq/bravo-vision)!

That's it! The user profile feature is now ready to be used. Feel free to test the feature in Bravo Vision and to add it to your existing apps.&#x20;


# Skeleton loader

How to build skeleton loading screens in Bravo Studio

One of the key features of Bravo is its **flexibility** both for the **design** and the **backend**. Thanks to leveraging the power of tools like Figma or Adobe XD together with the usage of [Bravo tags](https://bravostudio.notion.site/bravostudio/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8), we can have full control over how our apps look and feel.

### What is a skeleton loader?

> *In simplest terms,* [*Skeleton Loader*](https://blog.prototypr.io/skeleton-loader-an-overview-purpose-usage-and-design-173b5340d0e1) *is a static / animated placeholder for the information that is still loading. It mimic the structure and look of the entire view.*

Skeleton loaders create a perception of reduced waiting time, providing a good user experience for the app navigation. Good interaction design and good UX will always require some kind of feedback: **obvious, visible, understandable reactions from the UI**. While generic loaders like spinners are effective in many cases, skeleton ones give an immediate reaction and let users understand what is going to happen next.

{% embed url="<https://youtu.be/ue7CgpPAdUA>" %}

### How it works

To create a skeleton loader in Bravo, we are going to use the Bravo page states tags: `[state:default:NAME]` for the page that is loaded and `[state:loading:NAME]` for the skeleton one. Whenever the first one triggers an API request to load external data, the loading page will be shown immediately. Some points we need to keep in mind:

* The loading page will only appear when the related page loads external data
* Loading pages can’t have any data bound
* Page transitions won’t work on loading pages
* We can have one loading page per "default" page (will increase the page count)
* Loading pages won’t be shown when using pull to refresh

It is interesting to mention also that we can set up a \[state:loading] page (without :NAME) to be used by default on any screen of you app, and then use custom loading screens for specific pages. Full design power! 🙌

### Setup the design

![](/files/57xYFWi2Ax6lR5hbOMq8)

Once you have the main page designed, you can duplicate it and replace some elements by grey shapes. In our case we have also added a [LottieFile animation](https://docs.bravostudio.app/bravo-tags/interactive-component/component-lottie) at the top. Alternatively you can place a LottieFile with the whole skeleton design. There are [plenty of them](https://lottiefiles.com/search?q=skeleton\&category=animations) ready to use! Just find the one that better fits in with your design or create your own.

Then add the tag `[state:default:NAME]` to the main page and `[state:loading:NAME]` to the skeleton screen. Note that you need to replace NAME with a unique identifier of your choice. It is not required to be uppercase but it helps us to keep things organised.

And that’s it! Now every time the page loads data from the API, the skeleton loader will be shown 🎉

{% hint style="info" %}
You can see this example in action by [duplicating our sample app](https://projects.bravostudio.app/sample-apps/functionalities?appId=01G1T4Q3WNJ92RT2FTZY556CBS) or building the full setup from scratch duplicating the [design file](https://www.figma.com/community/file/1101792374472444768), copying the [Airtable base](https://airtable.com/shrcEMxmzh9gWzuzs) and [connecting both](https://docs.bravostudio.app/connnec-api/data-library-connecting-to-apis/set-up-api-requests/data-library-connect-to-any-api-get-request-for-lists) in Bravo Studio.
{% endhint %}

#### **Resources for this tutorial**

* [Sample app in Bravo Studio](https://projects.bravostudio.app/sample-apps/functionalities?appId=01G1T4Q3WNJ92RT2FTZY556CBS)
* [Design file](https://www.figma.com/community/file/1101792374472444768)
* [Example database](https://airtable.com/appJ97vgwpZbaWgCq/tblHJnz6RQ9ccVXxS/viwILpcYZetluBndY?blocks=hide)


# Create albums in your app with Bravo Infinite images

In this tutorial, we're going to demonstrate how you can set up a form to upload an unlimited number of pictures. Now in Bravo you can create a "loop" that allows users to submit a form and return to the same screen to repeat the process.

Here's what you'll need to do:

1. Design a [form with an image input](https://docs.bravostudio.app/bravo-tags/form-and-input-fields) and a submit button. Add a [<mark style="color:red;">`[refresh:always]`</mark>](/bravo-tags/mobile-actions/action-pull-to-refresh) tag to ensure the screen refreshes every time it’s opened.
2. Design a [modal](https://docs.bravostudio.app/bravo-tags/menus/modal-menu-1) containing an “upload more pictures” button and link it to the main form.

<figure><img src="/files/MpuhmY3tHFmB2HCmYqPR" alt=""><figcaption></figcaption></figure>

3. [Set up your API POST request](https://docs.bravostudio.app/connect-api/set-up-api-requests/creating-an-api-collection/data-library-connect-to-any-api-post-request).
4. [Bind the form](https://docs.bravostudio.app/bravo-tags/form-and-input-fields/data-biding-send-form-input-to-a-database) to the request and upon the form response action, select “Go to page” and choose the “Modal” page.

<figure><img src="/files/xB79yPB6y7BZ8aDetUdr" alt=""><figcaption></figcaption></figure>

5. Additionally, enhance the user experience by adding a [slider container](https://docs.bravostudio.app/bravo-tags/containers/container-horizontal-slider) to display the uploaded images.&#x20;
6. You can also add a delete icon with an <mark style="color:red;">`[action:remote]`</mark> tag binded to a Delete API request to removing images.

<figure><img src="/files/U9Z4ccfZywEbWZY3Op1m" alt=""><figcaption></figcaption></figure>

7. And that’s it! Test it with Bravo Vision.🎉

#### Example file

Duplicate his [Figma file](https://www.figma.com/file/UPvRk05BrHnMEDgGoMVPSR/Tips-%26-Tricks%3A-Uploading-Multiple-Images?type=design\&node-id=1-113\&mode=design\&t=mXRapqnbyGbjF3hz-0) and give it a try!

We hope you find this tip helpful! Do you have any other trick that you want to share with us? Please feel free to share your thoughts in our [Bravo community](https://community.bravostudio.app/home)! 😊


# Get your Figma ready for Bravo

**What is Bravorizing?**

**Bravorizing** is the process of setting up your design file for being converted into a fully functional native app by Bravo Studio. This process ensures that your designs are optimized and compatible for a seamless conversion and app development experience.

Bravorizing generally consists of:

* [**Structuring layers**](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy) as required by each Bravo component.
* [**Adding** **Bravo tags**](/set-up-design/setting-up-your-design-file/what-are-bravo-tags) to add functionality and structure.

Learn the art of *bravorizing* through our beginner's guide video. Below, find step-by-step instructions for an easy setup process. To familiarize yourself with its setup, make sure it's already Bravorized. You can also duplicate this [**sample design file**](/set-up-design/sample-design-files) to learn more.

{% embed url="<https://youtu.be/A_Ih0ETwMa0>" %}

{% embed url="<https://youtu.be/737wQ2AB1Fs>" %}

### Learn how to set up your design file before importing it to Bravo:

{% content-ref url="/pages/ACrqT37S6gANFp3cSgcr" %}
[Structuring the design: the layer hierarchy](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy)
{% endcontent-ref %}

{% content-ref url="/pages/RMwQ9MnTJko6ICXwFH0r" %}
[The container](/set-up-design/setting-up-your-design-file/the-container)
{% endcontent-ref %}

{% content-ref url="/pages/A0ah6yH6s5ZlD9eSfMxt" %}
[Bravo plugin for Figma](/set-up-design/bravo-plugin-for-figma)
{% endcontent-ref %}

{% content-ref url="/pages/-MXrEeGwIxR1H9L8F1ba" %}
[Bravo Tags: adding functionality to the UI elements](/set-up-design/setting-up-your-design-file/what-are-bravo-tags)
{% endcontent-ref %}

{% content-ref url="/pages/3smNzWid4GNWcY8I14ZN" %}
[App navigation](/set-up-design/setting-up-your-design-file/app-navigation)
{% endcontent-ref %}

{% content-ref url="/pages/-MfDz7zz4OgoSEUDE-CF" %}
[Sample design files](/set-up-design/sample-design-files)
{% endcontent-ref %}

{% content-ref url="/pages/-MhxgodWeJZkztsD-\_1-" %}
[Best Practices](/set-up-design/bravo-best-practices)
{% endcontent-ref %}

### Tutorial: Create your first app with Bravo

Follow this tutorial to learn how to create your first app with Bravo Studio. \
You will understand what Bravo is and its very basic concepts: Bravorizing, Bravo Tags, Binding and more:

<div align="center"><img src="/files/JMnerUSqjvnk0ZqZN6fx" alt=""></div>

Check out the complete tutorial here:

{% content-ref url="/pages/UGPIrQaqXZvUp9qzcDja" %}
[Create your first app](/get-started/create-your-first-app)
{% endcontent-ref %}


# Structuring the design: the layer hierarchy

Every app screen in your design file should be organized into the 3 levels described below. This is how Bravo can read and properly display your design. If you don't have this hierarchy, certain elements may look different or not show up in your app project.

## The Layer Hierarchy

Each level is inside ("nested" within) the level above.

* **Top-level layer:** always the **app page** component.
* **Second-level layer**: always a [**container**](/set-up-design/setting-up-your-design-file/the-container) component.
* **Third-level layer**: all the **UI elements** (text, shape, image, etc.)

![](/files/dX1uwfarguFYxBYOD4tv)


# Bravo Tags: adding functionality to the UI elements

A Bravo Tag is **a text string that you place in the component names of your design file**. After you import the design file into Bravo Studio, the layer with the Tag will turn into a mobile component or action in your final app (preview how it works with Bravo Vision).&#x20;

{% hint style="info" %}
Try out our official [Bravorizer plugin for Figma](/set-up-design/bravo-plugin-for-figma) and speed up your app building process!
{% endhint %}

If you are already a Bravo Tag pro, here is the [Bravo Tag Master List](https://www.notion.so/bravostudio/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8).

![](/files/-MjF-22hOnirrmwmm7Md)

## How to use Bravo Tags

Learn about the layer hierarchy. This is how you should organise the layers of your design file and determines in which layers you can place which tags.&#x20;

{% content-ref url="/pages/ACrqT37S6gANFp3cSgcr" %}
[Structuring the design: the layer hierarchy](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy)
{% endcontent-ref %}

Learn about an essential concept of Bravo: **the container**. This is a necessary element to have in the structure of every app page. &#x20;

{% content-ref url="/pages/RMwQ9MnTJko6ICXwFH0r" %}
[The container](/set-up-design/setting-up-your-design-file/the-container)
{% endcontent-ref %}

### How to add a Bravo tag to your design file

1\. In the [Bravo Tags Master List,](https://www.notion.so/bravostudio/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8) see which layer it's compatible with. Check out the sample design file or tutorial to see how to set up each tag.

![](/files/-MjF37wwPJW9_mofx0wy)

![](/files/-MjF4OW8kukz7J5AXiIA)

2\. Copy the tag.

![](/files/-MjF35oRxm7ym9reqGNb)

3\. Paste it into the name of the compatible layer.

![](/files/-MjF2quzW1XXvSYWbUil)

4\. Open your app project in [Bravo Vision](/get-started/bravo-vision-previewer) to preview the tag functionality.


# The container

{% embed url="<https://www.youtube.com/watch?v=zL1KEDMSHJg>" %}

For a design file to be Bravo-ready, you must add `[containers]`. These are components placed as a 2nd-level layer: inside ("nested" in) the app page and containing the different UI elements.

![](/files/d4MAsdKhqmv8SkmBSACH)

Containers have two main functions:

* **Wrap** the individual UI elements (images, text, etc.) in the design.
* Allow to create **lists** in the app page. Each container can be bound to API data that will make the container populate to a list in the app. To create a list, a placeholder list element needs to be created in the design, and wrapped in a container. How to connect the API data is further explained in the [step 3 of Create your first app](https://docs.bravostudio.app/get-started/create-your-first-app#step-3-importing-the-backend) section.

![](/files/RSrmbrC6kwOVVkuCuUwV)

## How to create a container

You can find below how to create a container, depending on the design tool you use.

{% content-ref url="/pages/Ut0ai92UkNJ4zvNzE7Sq" %}
[Setting up a container on Figma](/set-up-design/setting-up-your-design-file/the-container/setting-up-a-container-on-figma)
{% endcontent-ref %}

{% content-ref url="/pages/GeW8hCI4ym43FNQ0GQMB" %}
[Setting up a container on Adobe XD](/set-up-design/setting-up-your-design-file/the-container/setting-up-a-container-on-adobe-xd)
{% endcontent-ref %}

## Container guidelines

Containers must:

* Start the first container from the top of the app page component.
* Include the padding of your design within the container.
* They should not overlap one another \*.

*\*Except for the* [*top bar container*](/bravo-tags/containers/container-top-bar)*. You can have a top bar container and another container starting from the top edge of the page.*

![](/files/H6x2uuFfajNrdJDJh5Px)

If a container is <50% of the screen width, it will stack horizontally and then vertically down (when connected to API data to populate it into a list).

![](/files/itRnISRniFnWhFTxRPjD)

## Where to add a container

### Menu page <a href="#id-1.-is-this-page-a-menu" id="id-1.-is-this-page-a-menu"></a>

&#x20;Create a container around the menu area + add the menu tag.

![Blue overlay box denotes container.](/files/s0mTqkmfHlFGrtLW1hpN)

### **This page have a fixed top bar**

Create a container frame around the top-bar area + add the [top bar tag](/bravo-tags/containers/container-top-bar).

![Blue overlay box denotes container.](/files/GbI5KMminPhaZ1NppIn3)

### **This page has a list design that will be populated with API data later**

&#x20;Create one container around the list item design. In case you have other non-list UI elements, create containers around them too.

![](/files/FJMXKqOyf2zRyfXNP99u)

![](/files/1XXeBQIrRDGwNfnNTKRb)

### T**his screen has a text box that will be populated with API data and can be different amount of text from your design**

Create a container so that the text box is the bottom-most element in the container + add the [flexo text tag](/bravo-tags/components/component-flexible-text). If there is anything else below, create another container below.

![](/files/t2wkg17fJJG8CwETN31M)

### T**his screen has a design that needs to be the same aspect ratio across all device sizes (Ex: it must be full screen on all devices)**

Create a container frame around the design that needs to maintain its ratio to designed screen size + add the [aspect ratio to screen tag](/bravo-tags/containers/aspect-ratio-relative-to-screen).

![](/files/sbPw1alFri4pYSx9E105)

### If you don't need to split the page with containers, c**reate one container frame to enclose all the UI elements.**

![](/files/a4rlCt8HCSyhVAofhGl5)


# Setting up a container on Figma

## 🏗 How do I create a container? <a href="#how-do-i-create-a-container" id="how-do-i-create-a-container"></a>

&#x20; 1\. Select the `Frame` tool&#x20;

&#x20; 2\. Start from the left side of the app page frame and drag to the right side of the page, creating a frame that contains the UI elements. Make sure all the UI elements get nested in the container frame, in the third-level layer.

3\. Rename the layer to include the Tag `[container]`.

![](/files/dJ8cZ5pTKnfHlCt4U6AA)

Follow this tutorial to understand how to add a container to your design:

{% embed url="<https://www.figma.com/community/file/1383384053516441593>" %}


# Setting up a container on Adobe XD

## 🏗 How do I create a container? <a href="#how-do-i-create-a-container" id="how-do-i-create-a-container"></a>

&#x20;   1\. Select the **Rectangle** tool.

![](/files/HLdYsP0Fv6NKjoA4ONvM)

&#x20;  2\. Start from the left side of the app page frame and drag to the right side of the page, creating a rectangle that covers the area of the UI elements for the container.

{% hint style="info" %}
Rename it to "**area**" (if you'd like) to identify the purpose of the rectangle. The rectangle is used to create padding around the elements. Otherwise, the first element of the group will jump to the top left corner of the page.
{% endhint %}

![](/files/aOw3bXiOidSTnNCMTW1M)

&#x20;  3\. **Group** `command/ctrl + G` the elements and the rectangle "area" together.

&#x20;  4\. Add the Tag `[container]`to the name of the group layer.

![](/files/EWYO9Euz3ID9YtIhMhgL)

In addition to containers, you need to create the same "area" for any elements that require an interaction area bigger than the element itself. (i.e. a back arrow icon on its own might be too small for the user to tap).


# App navigation

The navigation between the app pages is set in the design tool (Figma or Adobe XD), by creating prototyping links between the pages.

![](/files/q9kogd5WQx8cklEkDyu0)

Creating these links has another important function: **passing data** between the API requests bound to the app pages.&#x20;

For instance, to create a page showing a list with several items, that navigates to a specific detail page when a certain item is pressed. In this case, the prototyping link will be created from the list container element to the app page with the detail information.

![](/files/vKMcEet8vlILvwfzx2l8)

{% hint style="info" %}
See [here](https://docs.bravostudio.app/get-started/create-your-first-app#step-3-importing-the-backend) how to create the API requests for the list and detail page setup.
{% endhint %}

Also, the prototyping tool will be used to specify the app **home screen**.&#x20;

## How to set up app navigation links

Below you can find how to create the prototyping links to create the app navigation, depending on the design tool you use.

{% content-ref url="/pages/xAY9OqYutwxplLEMbuGB" %}
[Setting up app navigation on Figma](/set-up-design/setting-up-your-design-file/app-navigation/setting-up-app-navigation-on-figma)
{% endcontent-ref %}

{% content-ref url="/pages/GeW8hCI4ym43FNQ0GQMB" %}
[Setting up a container on Adobe XD](/set-up-design/setting-up-your-design-file/the-container/setting-up-a-container-on-adobe-xd)
{% endcontent-ref %}


# Setting up app navigation on Figma

1\. In **Prototype** mode in Figma, **hover over a starting frame or element** until the connection node appears.

{% hint style="info" %}
The dimension of the element determines the touch area to trigger the navigation, so make sure it's not too small for the fingertip.
{% endhint %}

&#x20;2\. Click on the connection node and **drag link to the destination page**.

&#x20;3\. Make sure you also **connect the back buttons** to the previous frame. In case you have a [menu](/bravo-tags/menus), link the menu items to the corresponding screen.

4\. Finally, to add a **home screen** (the first screen the user will see when opening the app), add a new **flow starting point**. In case you have an [intro](/bravo-tags/intro-and-onboarding/page-intro) or/and a [login](/integrations/user-authentication) page, these screens will still appear before the home screen.

![](/files/ZzTEhi9jzeWXgKT2wWzW)

{% hint style="warning" %}
&#x20;There must be a single prototyping flow in the app.
{% endhint %}

### When do you NOT need a navigation link?

You do not need to link these page to any destination pages:

* [Intro page](/bravo-tags/intro-and-onboarding/page-intro).
* [Loading page](/bravo-tags/loading-experience/state-custom-loading-page#how-to-add-the-tag).
* Submit button in a [form](/bravo-tags/form-and-input-fields).
* Elements with [action](/bravo-tags/mobile-actions) tags.
* [Splash screen](/bravo-tags/app-icon-and-splash-screen#how-to-add-the-tag-1).

{% hint style="info" %}
**Bravo does not support the animations in Figma**. To apply page transitions, use the [transitions](https://www.figma.com/file/XOv0ej8UMlhw1THztGWwmy/Bravo-Sample%3A-Page-Transitions?node-id=0%3A1) Bravo Tags. The slide and modal menu include their own built-in animation.
{% endhint %}


# Setting up app navigation on Adobe XD

&#x20;  1\. Go to `Prototype` mode > **select an element** as the starting point of the navigation.

{% hint style="info" %}
The dimension of the element determines the touch area to trigger the navigation, so make sure it's not too small for the fingertip.
{% endhint %}

![](/files/wKGUvfkQNYZjAKr7Q23C)

&#x20;  2\. Click on the connection node and **drag link to the destination page**.

![](/files/Gtk1p2KzViLF7GcMxdOo)

&#x20;  3\. Add a home screen by setting the **blue Home icon.** In case you have an [intro](/bravo-tags/intro-and-onboarding/page-intro) or/and a [login](/integrations/user-authentication) page, these screens will still appear before the home screen.

![](/files/WNTH2j1fFJSm4sAZqA5W)

### When do you NOT need a navigation link?

You do not need to link these page to any destination pages:

* [Intro page](/bravo-tags/intro-and-onboarding/page-intro).
* [Loading page](/bravo-tags/loading-experience/state-custom-loading-page#how-to-add-the-tag).
* Submit button in a [form](/bravo-tags/form-and-input-fields).
* Elements with [action](/bravo-tags/mobile-actions) tags.
* [Splash screen](/bravo-tags/app-icon-and-splash-screen#how-to-add-the-tag-1).

{% hint style="info" %}
**Bravo does not support the animations in Adobe XD**. To apply page transitions, use the [transitions](https://www.figma.com/file/XOv0ej8UMlhw1THztGWwmy/Bravo-Sample%3A-Page-Transitions?node-id=0%3A1) Bravo Tags. The slide and modal menu include their own built-in animation.
{% endhint %}


# Bravo plugin for Figma

Use our Figma plugin to speed up your Bravorizing process!

{% embed url="<https://www.youtube.com/watch?v=4rn4Iuc6qqM>" %}
Promo video
{% endembed %}

The Bravorizer is the [Bravo Studio plugin for Figma](https://www.figma.com/community/plugin/1149380850484102424/Bravorizer). It’s your assistant when you need to make an app design “Bravo compatible”, so it’s ready to sync with your Bravo app project.

## Getting started with the plugin

1. Open the [Bravorizer page on Figma](https://www.figma.com/community/plugin/1149380850484102424/Bravorizer) and click **Try it out** to install the plugin on your account. If you're not authorized in Figma, you will need to sign in first.
2. Once it's done, you can run the Bravorizer plugin from the Resources panel by hovering over the plugin name and click “Run”.

## How to use the UI presets

The UI presets section is designed to accelerate the app creation process by providing a pre-made library of UI presets, complete with properly configured tags. \
Simply "**copy & paste**" the UI page into your Figma File, and begin customizing the preset with your unique design style.

<figure><img src="/files/WByalbU0C5l6mEroGHCr" alt=""><figcaption></figcaption></figure>

## How to use the Bravo Tagger

The Bravo Tagger section of the plugin helps you quickly add [Bravo tags](https://docs.bravostudio.app/set-up-design/what-are-bravo-tags) to the layer names.

A Bravo Tag is a text string that you place in the layer names of your design file. After you connect the design file with Bravo Studio, the layer with the tag will turn into a native mobile component or action in your final app (previewable with Bravo Vision).

<figure><img src="/files/ANnrQdJV5WU0XKXKNGRS" alt=""><figcaption></figcaption></figure>

**How to add a tag**

1. Once you are running the plugin, select at least one layer to add a tag. Under “Selected Layers”, you can confirm the selected layer and any existing tag the layer has.
2. All the Bravo Tags are listed below, separated by categories. To find a tag, you can either browse the list or type in the search bar.
3. Once you found the tag you want to add to the layer(s), click on the tag, it will appear next to the layer name above under “Selected Layers”. Click “Add tags” to confirm and the tags will be added to the layer name.

**How to remove a tag**

**Option 1:** Manually edit by double clicking the layer name from the Layers panel in Figma and delete the tag.

**Option 2:** In the Bravorizer plugin, select the layer(s) and click the “X” icon next to each tag-detected on the layer.

**Option 3:** In the Bravorizer plugin, select the layer and click “Remove tags” to remove all the tags from the layer(s) selected.

**How to edit a tag**

You shouldn’t need to edit a tag as the plugin contains all the tags with their correct spelling. In the rare case that you need to, for a valid compatibility reason, simply manually edit the tag by double-clicking the layer name from the Layers panel in Figma.

## How to use the Tag Checker

The Tag Checker reviews the selected layer(s) to make sure all the tags are correctly placed before you connect the design with your Bravo app.

1. When you are on the Tag Checker section of the plugin, select a layer. We recommend selecting one or multiple app screens to thoroughly check the entire design.
2. The Tag Checker will display errors (in grey) or suggestions (in blue) regarding the layer(s) selected.

<figure><img src="/files/ZlJQJzZ6fmlQgly2YSXf" alt=""><figcaption></figcaption></figure>

3\. If there are no errors or suggestions detected, your design (or at least the selected layers) is ready to be connected to Bravo! Open [Bravo Studio](https://projects.bravostudio.app/login) to [create a new app project](https://docs.bravostudio.app/get-started/your-bravo-app-projects/create-a-project/creating-an-app-project-with-figma) from the design file or [update an existing one](https://docs.bravostudio.app/get-started/your-bravo-app-projects/app-projects-the-app-project-page#3.-toolbar).

<figure><img src="/files/MmyV6dWxO00i70ixIkJj" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Please note:** changes in Figma don't auto-sync with Bravo. Your Bravo app will only update if you press the **Update** icon in **Bravo Studio**.
{% endhint %}

## How to use the AI assistant

The Ask AI section is an AI assistant ready to answer questions directly from our documentation. Ask any question you have about Bravo and get help directly on the stop


# Sample design files

Use these *bravorized* design files to learn Bravo! They include containers and Bravo Tags and they are ready to be imported into Bravo Studio. You can also find them in the [Sample Apps](https://projects.bravostudio.app/sample-apps/complete-apps) section.

{% hint style="info" %}
**Bravorizing** is the process of setting up your design file for being converted into a native app by Bravo Studio. It consist of using containers, structuring layers and using Bravo tags. [Learn more on what bravorizing is.](/set-up-design/setting-up-your-design-file)
{% endhint %}

## <img src="/files/-MfE-fR4nqFAan6H1bAC" alt="" data-size="line"> Figma files

Duplicate our *bravorized* sample Figma files from our [Figma community page](https://www.figma.com/@bravostudio) to learn more about how a design needs to be set up for being Bravo-ready.&#x20;

Some examples:

{% embed url="<https://www.figma.com/community/file/1134788542858691041>" %}

{% embed url="<https://www.figma.com/community/file/1065318978437109787>" %}

{% embed url="<https://www.figma.com/community/file/979785681292985266>" %}

{% embed url="<https://www.figma.com/community/file/1026897938184618660>" %}

Head over to our [Figma community page](https://docs.bravostudio.app/set-up-design/www.figma.com/@bravostudio) for more sample design files.

## <img src="/files/-MfE-h_oSwTbspxwoTQ2" alt="" data-size="line"> Adobe XD files

Download these *bravorized* Adobe XD design files to learn more about how a design needs to be set up for being Bravo-ready.

{% tabs %}
{% tab title="XD: Bravo functionalities" %}
{% file src="/files/-MfE032MTT2Rbo1S-9wJ" %}
Bravo sample: Mobile Actions
{% endfile %}

{% file src="/files/-MfE032NFtON\_L\_syjUk" %}
Bravo sample: Audio
{% endfile %}

{% file src="/files/-MfE032OQvB1653HW8B9" %}
Bravo sample: Component States
{% endfile %}

{% file src="/files/-Mi6zW0hWXxeP\_-5E8sS" %}
Bravo sample: Custom Loading
{% endfile %}

{% file src="/files/-Mi6zxy-Nt03OKh0TEsX" %}
Bravo sample: Hide Tabs Menu
{% endfile %}

{% file src="/files/-Mi7-6uD7v2JawC4anLT" %}
Bravo sample: Intro Pages
{% endfile %}

{% file src="/files/-Mi7-AV9c5Z9UAxI6mEV" %}
Bravo sample: Login
{% endfile %}

{% file src="/files/-Mi7-DwRd3o5J9LY0KSA" %}
Bravo sample: Modals
{% endfile %}

{% file src="/files/-Mi7-GkG1uSPe58a3Utr" %}
Bravo sample: Page States
{% endfile %}

{% file src="/files/-Mi7-LNErNj\_MKLHPmTZ" %}
Bravo sample: Page Transitions
{% endfile %}

{% file src="/files/-Mi7-PequZVVnG5trrUG" %}
Bravo sample: Pop-ups
{% endfile %}

{% file src="/files/-Mi7-Ss1eEC-59OCaufB" %}
Bravo sample: Push Notifications
{% endfile %}

{% file src="/files/-Mi7-YCj7gmkJQVOCJWz" %}
Bravo sample: Reveal Animations
{% endfile %}

{% file src="/files/-Mi7-al3JC76UrLFTBJ5" %}
Bravo sample: Rich Text
{% endfile %}

{% file src="/files/-Mi7-iqSkgG1mDtiKzHP" %}
Bravo sample: Search & Filter
{% endfile %}
{% endtab %}

{% tab title="XD: apps" %}
{% file src="/files/-MfE-CljK-W4aKyQHJTy" %}
Bravo sample app: Travel app 2.0
{% endfile %}

{% file src="/files/-Mi6zeGfA-ntOqXbNp5H" %}
Bravo sample app: Foodgram
{% endfile %}

{% file src="/files/-Mi6zr56KreeYVzFR8rM" %}
Bravo sample app: Foodies
{% endfile %}

{% endtab %}
{% endtabs %}


# Best Practices

### **Screens, frames & layers**

* Make sure all your screen frames are the same width-wise.
* Include a [splash screen](/bravo-tags/app-icon-and-splash-screen#how-to-add-the-tag-1) - it gives Bravo a reference point for displaying your design proportionally on all devices.
* Try to design just the necessary screens and then connect them to real data through an API.
* Make sure your visual elements are within their parent frame. Whatever is outside a frame may be cut off even if it is visible in Figma.
* Delete any hidden layers not being used.
* If there are specific layers you don't want Bravo to import, use the tag `[skip]`.
* Avoid too many nested groups. Ungroup layers when is not necessary. Keep in mind that each group is a new element to be imported, and too many elements might result in hitting an [import limitation error](/good-to-know/troubleshoot/errors-when-importing).
* Use the **\[component:svg]** tag to convert multiple elements into just one, when you don't need to bind any data to them.

### **Vectors, SVGs, custom shapes**

* Put a group around vector shapes to improve performance of the Figma-Bravo sync.&#x20;
* "Outline stroke" any design made up of strokes (like line icons) to turn them into vector shapes.
* If you have custom vector shapes in your design, make sure they are completely closed.
* Flatten your vector shapes into one vector.
* SVGs/vectors are "fit" to frame by default, as they are normally used for icons.
  * If you want the SVG to "fill" a frame (i.e. for backgrounds), add the tag `[shape:fill]` to the vector layer

### **Images**

* If connecting images from a database, set the image fill in your Figma file based on how you want the image to display (fit or fill)
* *Crop* and *tile* are not supported
* For having a circular image, use a rectangle shape with at least 30 corner radius. We don't support ellipsis yet.

### **Effects (shadow, blur)**

* If you have 2+ effects (i.e. shadow, blur) on one layer. Add the tag `[component:svg]` to the layer.

### **Text**

* Make sure your text box is bigger than the text content inside, or your text will be cut once imported to Bravo. On Adobe XD, use **Fixed Size** rather than Auto Height or Auto Width.
* When using a [`[flexo]`](/bravo-tags/components/component-flexible-text) text box, make sure there is only one of them per container and it's the bottom-most element.


# Bravo Tags Master List

Copy and paste these tags into the layer names in your design file and see your app come to life with Bravo Vision.

{% hint style="info" %}
[Learn how to use Bravo Tags](/set-up-design/setting-up-your-design-file/what-are-bravo-tags)
{% endhint %}

### Figma Plugin

Speed up your Bravorizing process with our ready-made UI presets.

{% hint style="info" %}
Try out our official [Bravorizer plugin for Figma](https://www.figma.com/community/plugin/1149380850484102424) and speed up your app-building process!
{% endhint %}

### Glossary

* **Element** = the app element created from the tag
* **Bravo Tag** = the tag itself
* **Layer Type** = the type of layer you can place this tag on
* **Tag Type** = Bravo categorization of the tag

### 🗂 Menus

{% tabs %}
{% tab title="Tabs Menu" %}
To create a menu with tabs you will need this tag:

```
[menu:tabs]
```

The menu that stays fixed on every screen is a bottom navigation bar.\
👉 Where to label the tag: **Top-level app page**

[See full docs](/bravo-tags/menus/tabs-menu)
{% endtab %}

{% tab title="No menu tabs" %}
To hide the menu with tabs on a specific page you need this tag:

```
[nomenu]
```

Define which pages to hide the tab menu\
👉 Where to label the tag: **Top-level app page**<br>

[Sample Figma setup](https://www.figma.com/community/file/981942888856892917)<br>
{% endtab %}

{% tab title="Slide Menu" %}
To hide the menu with tabs on a specific page you need this tag:

```
[menu:slide]
```

The menu opens by sliding in from the left side of the screen.\
👉 Where to label the tag: **Top-level app page**

[See full docs](/bravo-tags/menus/slide-menu)
{% endtab %}

{% tab title="Modal Menu" %}
To create a menu that will be opening like a modal you will need this tag:

```
[menu:modal]
```

The menu slides in from the bottom and covers the entire screen.\
👉 Where to label the tag: **Top-level app page**\
\
To close the Modal menu you also will need to set up this tag in the element that will trigger the close action:

```
[action:close] 
```

\
\
👉 Where to label the tag: **Any layer (except top-level)**

[See full docs](/bravo-tags/menus/modal-menu)
{% endtab %}
{% endtabs %}

### 📦 Containers, topbar & others

{% tabs %}
{% tab title="Container" %}
In order to properly display your content, you must enclose it within a container tag. Additionally, if you wish to repeat this container tag multiple times, you can use it to create a list of items.&#x20;

```
[container]
```

The container defines blocks of an app page by their distinct behaviors.\
👉 Where to label the tag: **2nd-level container**

[See full docs](/set-up-design/setting-up-your-design-file/the-container)
{% endtab %}

{% tab title="Top Bar" %}
The Top bar is a container that could be fixed or not at the top of each page.

**Fixed Top bar**

```
[container:top-bar]
```

In this case, the Top bar container fixes its position to the top of the screen and does not scroll with the rest of the screen.

**Hide on scroll Top Bar**

```
[container:top-bar:hidescroll]
```

The top bar container will hide as you scroll up the page, and reappear when you scroll down.

**Show on scroll Top Bar**

```
[container:top-bar:showscroll]
```

The top bar container will show as you scroll down the page, and will remain until you scroll up to the top again.

\
👉 Where to label the tag: **2nd-level container**<br>

[Sample Figma setup](https://www.figma.com/community/file/981972505586768390)

[See full docs](/bravo-tags/containers/container-top-bar)
{% endtab %}

{% tab title="Aspect Ratio" %}
The height of the container is calculated with the screen height, so they won't maintain the designed aspect ratio but is useful when you want a container to be relative to the screen.

```
[aspectratio:screen]
```

👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/aspect-ratio-relative-to-screen)
{% endtab %}

{% tab title="Layer (sticky element)" %}
A container that fixes its position on-screen and does not scroll with the rest of the screen.

```
[layer]
```

\
👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/layer-sticky-element)
{% endtab %}
{% endtabs %}

### 🎠 Sliders

{% tabs %}
{% tab title="Sliders horizontal scroll" %}
Slides a collection of containers horizontally. Each tag is a different animation.

```
[container:slider:horizontal] 
```

```
[container:slider:default]
```

```
[container:slider:crossfade]
```

```
[container:slider:cube]
```

```
[container:slider:pager]
```

```
[container:slider:parallax]
```

```
[container:slider:rotate] 
```

```
[container:slider:zoom]
```

\
👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/container-horizontal-slider)\
Adds a dots indicator at the bottom of the slide element, with the specified color (use HEX code). Place it on the same layer as the `[container:slider]` tag.
{% endtab %}

{% tab title="Slider indicators" %}
**Indicator + color setup**

```
[slider-indicator:#FFFFFF]
```

```
[slider-indicator:<active_color>:<inactive_color>]
```

\
\
👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/container-horizontal-slider)
{% endtab %}

{% tab title="Automatic sliders" %}
The slider will move automatically every 5 seconds. \
Place it on the same layer as the `[container:slider]` tag.<br>

```
[slider-automatic:5]
```

Slider will move automatically **every x seconds**.&#x20;

For example **8 seconds** `[slider-automatic:8]`

**📍 Where to add the tag:** on the same layer as the \[container:slider] tag.

\
👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/container-horizontal-slider)
{% endtab %}

{% tab title="Infinite sliders" %}
After the last slide, the first slide will be shown, so the user can swipe in one direction infinitely. Place it on the same layer as the `[container:slider]` tag.

```
[slider-infinite]
```

\
👉 Where to label the tag: **2nd-level container**

[See full docs](/bravo-tags/containers/container-horizontal-slider)
{% endtab %}
{% endtabs %}

### 💡 Modal pages

{% tabs %}
{% tab title="Modal page default (100%)" %}
A screen that slides in from the bottom and covers 100% of the previous screen. Not scrollable. Swipe down the screen down to close.

```
[page:modal]
```

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/967380255651810770)<br>
{% endtab %}

{% tab title="Partial modal page" %}
A screen that slides in from the bottom and covers a percentage of the previous screen. \
It is scrollable and you can make it as long as you want.<br>

```
[page:modal:<NUMBER%>]
```

i.e. **\[page:modal:30%]**

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/967380255651810770)
{% endtab %}

{% tab title="Fixed Modal page" %}
A partial screen that slides in from the bottom and covers a part of the previous screen. Not scrollable. Swipe down the screen down to close.<br>

```
[page:modal:fixed]
```

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/967380255651810770)
{% endtab %}

{% tab title="Modal iOS card" %} <mark style="color:red;">**⚠️ iOS-only feature ⚠️**</mark>\
\
A screen that covers a majority of the screen. It is scrollable and you can make it as long as you want. Swipe down the screen to close. If you are using this feature on Android, will display the default modal page.

```
[page:modal][ios:cards]
```

You will need 2 tags

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/967380255651810770)
{% endtab %}
{% endtabs %}

### 🎉 Pop-up pages

{% tabs %}
{% tab title="Default" %}
A screen that pops over your other app pages. To close the popup will require the `[action:close]` tag

```
[page:popup]
```

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/981969825191369221)<br>
{% endtab %}

{% tab title="Blur background" %}
Get a blurred effect on the background behind the popup.

```
[page:popup:blur]
```

To close the popup will require the `[action:close]` tag\
\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/981969825191369221)
{% endtab %}

{% tab title="Color Background" %}
Change the color behind the popup to get more customization other app pages.&#x20;

```
[page:popup:<color-code>]
```

e.i. \[page:popup:#FFFFFF]<br>

To close the popup will require the `[action:close]` tag

\
👉 Where to label the tag: **Top-level app page**

[Sample Figma setup](https://www.figma.com/community/file/981969825191369221)
{% endtab %}
{% endtabs %}

### 👋 Intro & Onboarding

{% tabs %}
{% tab title="Intro" %}
Displays an Intro screen of your choice: \
**1**) every time the app user opens the app or **2**) only the first time

```
[intro:always]
```

```
[intro:once]
```

&#x20;To close the intro will require the `[action:closeintro]` tag

<mark style="color:red;">**⚠️ DO NOT**</mark> <mark style="color:red;"></mark><mark style="color:red;">link the element that triggers the close action to any page.</mark> \ <mark style="color:red;">For example to</mark> <mark style="color:red;"></mark><mark style="color:red;">**HOME page**</mark>

\
👉 Where to label the tag: **Top-level app page**

[See docs](/bravo-tags/intro-and-onboarding/page-intro)<br>
{% endtab %}

{% tab title="Post-login " %}
Displays a post-login screen after a login or register action. It can be displayed only once (the first time a user logs in or registers), or always. \
\
It will be displayed after the login or register action, and before the home screen.

```
[post-login:always]
```

```
[post-login:once]
```

&#x20;To close the popup will require the `[action:close]` tag

\
👉 Where to label the tag: **Top-level app page**

[See docs](/bravo-tags/intro-and-onboarding/post-login-page-onboarding)
{% endtab %}
{% endtabs %}

### 💎 Components (Rectangle level)

{% tabs %}
{% tab title="Video " %}
An audio-less video that autoplays when a user is on the app screen. The video will replace the content of the rectangle. Supports URL ending in .**mp4.**&#x20;

```
[component:video:https://google.com/test.mp4]
```

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/component-autoplay-video)<br>
{% endtab %}

{% tab title="GIF" %}
A GIF will replace the content of the rectangle.

```
[component:gif:https://google.com/test.gif]
```

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/component-gif)
{% endtab %}

{% tab title="Lottie" %}
A Lottie will replace the content of the rectangle.

```
[component:lottie:LOTTIE_JSON_URL]
```

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/component-lottie)
{% endtab %}

{% tab title="Lottie animated" %}
These are the tags you can use in the design file to implement the toggle component.

**Animated component**&#x20;

```
[component:stateful-lottie:<url.json>]
```

**Input component form**

```
[component:input-stateful-lottie:<url.json>]
```

The Lottie animation frame goes from 0 to 180. We will set a `<custom-frame>` of 90 as it's where we want the animation to stop.

<mark style="color:red;">`[component:input-stateful-lottie:<url>:`</mark><mark style="color:blue;">`90`</mark><mark style="color:red;">`]`</mark>

The animation plays as follows:\
To enable, on tap, the animation plays from 0 to 90,\
To disable, on tap, the animation plays from 90 to end.

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/lottie-animated-component)
{% endtab %}

{% tab title="Webview" %}
A web page will replace the content of the rectangle.

```
[component:web-view:https://bravostudio.app]
```

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/component-webview)
{% endtab %}

{% tab title="SVG" %}
If your vector shape layer ***looks funky*** in **Bravo Vision** or if a layer has ***2+ effects***, add this tag to any element, group or frame to allow Bravo to render it as it looks in Figma.

```
[component:svg]
```

\
👉 Where to label the tag: **Inside a container frame in any Shape layer (3rd level)**

:warning: A group with this tag cannot be bounded, please ensure it consists of a single element.
{% endtab %}

{% tab title="Zoomable image" %}
Creates a zoomable image. The zoom is trigged by pinch gesture.

```
[component:imagezoom]
```

\
👉 Where to label the tag: **Inside a container frame in a Image layer (3rd level)**

[See Sample Figma file](https://www.figma.com/community/file/1030830462731458065)\ <br>
{% endtab %}

{% tab title="Shape fill" %}
SVGs/vectors are "fit" to container by default, as they are normally used for icons. With this tag, the SVG will be "fill" to container, which is useful for backgrounds.

```
[shape:fill]
```

\
👉 Where to label the tag: **Inside a container frame in a Shape layer (3rd level)**<br>
{% endtab %}
{% endtabs %}

### 📈 Interactive Components (Rectangle level)

{% tabs %}
{% tab title="Maps with markers" %}
Create an interactive map component with custom markers

To create the interactive map:

```
[component:map:interactive]
```

To create the map as a fixed image with the markers, not movable or zoomable:

```
[component:map]
```

To specify statically the centre of the map and the zoom value:

```
[component:map:<latitude>:<longitude>:<zoom>]
[component:map:interactive:<latitude>:<longitude>:<zoom>]
```

To require location permissions to the user in a certain app screen (place the tag in the top-level app page):

```
[require:location]
```

To create a custom marker:

```
[asset:marker:default]
```

👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/map-with-markers)
{% endtab %}

{% tab title="Charts" %}
Bravo supports 2 chart types at the moment: **pie** and **bar**. Depending on the data you want to visualize, you may find the most suitable format.

To create a pie chart:

```
[component:chart:pie]
```

To create a bar chart:

```
[component:chart:bar]
```

👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/charts)
{% endtab %}
{% endtabs %}

###

### 📝 Components (Text level)

{% tabs %}
{% tab title="Flexo" %}
A GIF will replace the content of the rectangle.

```
[component:gif:https://google.com/test.gif]
```

\
👉 Where to label the tag: **Inside a container frame in a Rectangle shape (3rd level)**

[See docs](/bravo-tags/components/component-gif)
{% endtab %}

{% tab title="Rich Text" %}
Display text with Markdown or HTML styling. Useful for APIs that send text styling.

#### **Mark Down style**

Text with Markdown styling

```
[component:text:md]
```

#### **HTML style**

Text with HTML styling.

```
[component:text:html]
```

Supported HTML elements:

```
<a>
<b>
<big>
<blockquote>
<br>
<cite>
<div>
<em>
<font>
<h1>
<h2>
<h3>
<h4>
<h5>
<h6>
<i>
<li>
<p>
<small>
<span>
<strike>
<strong>
<sub>
<sup>
<u>
<ul>
and attributes: size, color
```

\
👉 Where to label the tag: **Inside a container frame in a Text layer (3rd level)**

[See Sample Figma file](https://www.figma.com/community/file/981941729280829940/bravo-sample-rich-text)
{% endtab %}
{% endtabs %}

### ✨ Transitions

{% tabs %}
{% tab title="Slide" %}
2nd page slides over current page with a parallax effect.

**Transition direction**

```
[transition:slide:left]
```

```
[transition:slide:right]
```

```
[transition:slide:up]
```

```
[transition:slide:down]
```

👉 Where to label the tag: **Top-level app page**

[Sample Figma file](https://www.figma.com/community/file/981975323423403527)
{% endtab %}

{% tab title="Move" %}
2nd page slides over current page at a consistent speed.

**Transition direction**

```
[transition:move:left]
```

```
[transition:move:right]
```

```
[transition:move:up]
```

```
[transition:move:down]
```

👉 Where to label the tag: **Top-level app page**

[Sample Figma file](https://www.figma.com/community/file/981975323423403527)
{% endtab %}

{% tab title="Push" %}
2nd page pushes current page out of the screen.

**Transition direction**

```
[transition:push:left]
```

```
[transition:push:right]
```

```
[transition:push:up]
```

```
[transition:pushdissolve:down]
```

👉 Where to label the tag: **Top-level app page**

[Sample Figma file](https://www.figma.com/community/file/981975323423403527)
{% endtab %}

{% tab title="Dissolve" %}
2nd page fades in while the current page fades out.

```
[transition:dissolve]
```

👉 Where to label the tag: **Top-level app page**

[Sample Figma file](https://www.figma.com/community/file/981975323423403527)
{% endtab %}

{% tab title="Instant" %}
There is no transition from page to page

```
[transition:instant]
```

👉 Where to label the tag: **Top-level app page**

[Sample Figma file](https://www.figma.com/community/file/981975323423403527)
{% endtab %}
{% endtabs %}

### 🎧 Audio

{% tabs %}
{% tab title="Play audio" %}

```
[action:play:URL] or [action:play]

Use [action:play] if you are getting the URL by API.
```

Plays the MP3 audio track. When this element is visible, the **pause** element will be invisible, and vice versa.

Replace `URL` with an actual URL ending in **.mp3**

**📍 Where to add the tag:** Any layer, except top-level and container.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Pause audio" %}

```
[action:pause]
```

Pauses the MP3 audio track. This element will be invisible until user clicks the **play** element.

**📍 Where to add the tag:** Any layer, except top-level and container.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Progress Bar" %}

<pre><code>[audio:progress:#<a data-footnote-ref href="#user-content-fn-1">FFFFFF</a>]
</code></pre>

You can change the color by setting the HEX color in the tag.

Displays a progress bar to move forward or rewind the audio track. The appearance will be the native component for each device.

**📍 Where to add the tag:** A Rectangle layer.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Play audio in background" %}

```
[audio:background]
```

**Optional tag.** If this tag is included, audio files will continue playing when the app is open in the background. In order to stop the audio, users will have to return to the page where the audio was started and tap pause.

If this tag is **not** included, audio files will only play when its page is visible and will pause otherwise.

**📍 Where to add the tag:** Any layer, except top-level and container.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Loading indicator" %}

<pre><code><strong>[audio:loading]
</strong></code></pre>

**Optional tag.** The element that will be displayed from the moment the **play** element is clicked until the audio file is ready to be played, along with the **pause** element.

**📍 Where to add the tag:** Any layer, except top-level and container.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Current played time" %}

```
[audio:currenttime]
```

Displays the progressive playing time & the total time of the audio track.

**📍 Where to add the tag:** A text layer.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}

{% tab title="Total time" %}

```
[audio:totaltime]
```

Displays the total time of the audio track.

**📍 Where to add the tag:** A text layer.

[See Sample Figma file](https://www.figma.com/community/file/984482687373329643?fuid=735161339401487360)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Make sure your phone it's not on **mute.**
{% endhint %}

🚧 This page is under construction, full Master List here: \
<https://bravostudio.notion.site/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8>

[^1]: Change to your custom color


# Menus


# Modal Menu

The menu that slides in from the bottom and covers the entire screen.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag, placed on a top-level app page, creates a menu that slides in from the bottom and covers the entire screen.

**📍 Where to add the tag:** A top-level app page

```
[menu:modal]
```

![](/files/zypNwqvx2Mit0B4iy8Sn)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a menu design that covers the whole screen.

&#x20;   2\. Create a 2nd-level container around the menu design.

![](/files/MCl49nfiHi52wMMR9rIz)

&#x20;   4\. \[Bonus Tag] If you have a close element in your menu design, you can add the tag \[action:close] to close the menu.

![](/files/IUFOLfQ3ZRBMdk3S8b5d)

&#x20;   5\. Link each menu item to the app page you want it to open.

&#x20;   6\. Link the menu icon on any app page to the menu.

![](/files/gbkrQEL2UAe2xKGFUu8S)

{% hint style="info" %}
Make sure the Starting app page is on your "home" app page, not the menu screen
{% endhint %}

&#x20;   7\. Import to Bravo & preview on Bravo Vision 🚀

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1382718711989757462>" %}


# Modal pages

Pages that slides in from the bottom and covers the screen.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag, placed on a top-level app page, creates a page that slides in from the bottom and covers the  screen.

**📍 Where to add the tag:** A top-level app page

![](/files/MthOMvdR1ewtAb1BC99Q)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a Modal page design.
2. Use the tag that you prefer the most for modal page.

## Types of modal pages

### Page modal 100%

This modal will always be 100% of the mobile screen and this is a fix modal. Use this tag:

```
[page:modal]
```

![](/files/tpS6W9Irx2b6PPdRqSe8)

### Page modal % Size

Define the percentage number of the screen that your modal will shown up. Could be scrollable! Make it as long as you want. Several samples here:

```
Size 30% [page:modal:30%] 
Size 50% [page:modal:50%]
Size 70% [page:modal:70%]
Size 90% [page:modal:90%]
```

![](/files/SeGx119ca8l96nEby3cf)

### Page Modal Fixed Size

Add the following tag in case you want the modal to be fixed:

```
Page Fixed [page:modal:fixed]
```

![](/files/ZxHdrDI1nZDUmkB1XYK9)

### iOs Cards Modal Type

This type of Modals are just working in iOs. This will be a 100% screen modal and scrollable! Add this tag:

```
iOs cards [page:modal][ios:cards]
```

![](/files/dNe0ATZlrRpRwn0xdItU)

{% hint style="info" %}
🔥 Important: Noticed that for the experience you will close them with a swipe down.
{% endhint %}

Now you can do the prototyping! Import to Bravo & preview on Bravo Vision 🚀

![](/files/mEbN2JQqNF0XLwsMxvkz)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/967380255651810770/bravo-sample-modal-pages>" %}


# Tabs Menu

The menu that stays fixed on every screen as a bottom navigation bar.

## 👉 **The Tag**

This tag, placed on a top-level app page, creates a fixed bottom navigation bar on every screen of the app.

**📍 Where to add the tag:** A top-level app page

```
[menu:tabs]
```

![](/files/dkJrT993JmRNHxTJ3EXG)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a tabs menu design (it can be any height).

![](/files/RHzDNHmTwDokxTI1lHdh)

&#x20;   2\. Create a 2nd-level container around the menu design.

![](/files/ugs9LfoWIw8IpbuW7cXS)

&#x20;  3\. **Copy & paste** the tag into the layer name of the **top-level app page.**

![](/files/xEXjR0VEDb7jCXibgVWx)

&#x20;   4\. Link each menu item to the app page you want it to open.&#x20;

{% hint style="warning" %}
Make sure there are at least 2 menu items linked. If you only have one menu item linked, the tabs menu will not show.
{% endhint %}

![](/files/q2ueV3T89GHCAk13q3r3)

{% hint style="info" %}
Remember not to place the starting flow of the prototyping in the tab menu frame. Instead added in the page you want the user to land first. [Learn more ](/set-up-design/setting-up-your-design-file/app-navigation/setting-up-app-navigation-on-figma)
{% endhint %}

<figure><img src="/files/aekyu7Dn4H7bZkQOWtNU" alt=""><figcaption></figcaption></figure>

&#x20;   5\. Import to Bravo & preview on Bravo Vision 🚀

{% hint style="info" %}
In case you want to implement **active states** for the buttons in the tabs menu, check out [this example design file](https://www.figma.com/community/file/938484133762361804).
{% endhint %}

{% hint style="info" %}
You can also hide your tab menu on certain pages by adding the `[nomenu]` tag. *See the example file*
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1384471524300479110>" %}

{% embed url="<https://www.figma.com/community/file/981942888856892917>" %}


# Pop Up pages

Pop-up pages can be effective for drawing attention to specific information or encouraging user interaction.

## 👉 **The Tag**

By using this new tags you will be available to make new pages to popup!

**📍 Where to add the tag:** A top-level app page.

![](/files/Hiq7s7xpaDOY0xeuYwfe)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a Pop up design.
2. Use the tag that you prefer the most for your pop-up.

### Normal Pop Up

Use this tag:

```
Normal Popup [page:popup]
```

![](/files/9H2liWe9LVFpYA1ML7QV)

### Rounded Corners Pop Up

In case you want rounded corners use this tag:

```
Rounded Corners Popup [page:popup] 
```

![](/files/K12uRbTBvNKS82NJPIRY)

### Color Background Pop Up

In case you want a color background Pop up use the follow tag:

```
Color Background Popup [page:popup:#CCFAFF00]
```

![](/files/rgCq0V8b5uMFZ2IeuRpd)

### Blur Background Pop Up

You want a blur background Pop Up:

```
Blur Background Popup [page:popup:blur] 
```

<figure><img src="/files/YovOoQfSv5ajxu2uhJdt" alt=""><figcaption></figcaption></figure>

### Slider Pop Up

This is the case if you need to show more than one pop-up at a time.

```
Slider popup[page:popup]
Slide [container:slider:horizontal]
```

![](/files/vREBeBlWxVGllxXE2aXM)

{% hint style="warning" %}
🔥 Important: To Close the popup the action close will be required:

\[action:close]
{% endhint %}

Now you can do the prototyping! Your Pop Up is ready to use. Import to Bravo & preview on Bravo Vision 🚀

<figure><img src="/files/i54F90MTHimt9IpDqk8D" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
it's important to use the Pop up pages judiciously to avoid creating a negative user experience, as excessive or intrusive pop ups can be disruptive and may lead to a poor user experience.
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981969825191369221>" %}


# Slide Menu

The menu that opens by sliding in from the left side of the screen.

## 👉 **The Tag**

This tag, placed on a top-level app page, creates a menu that slides in from the left side of the screen. Any element linked to this screen will trigger the menu to open.

**📍 Where to add the tag:** A top-level app page

```
[menu:slide]
```

![](/files/-MfcSs3zGfuB1S5rJq9I)

## 🏷️  **How to add the tag**

1. On a blank app page, create a side menu design (it can be any width).
2. Create a 2nd-level container around the design (what you want to slide out).
3. **Copy & paste** the tag into the layer name of the **top-level app page.**
4. Link each menu item to the app page you want it to open.
5. Link the menu icon on any app page to the menu.

   Make sure the **Starting app page** is on your "home" app page, not the menu page
6. Import to Bravo & preview on Bravo Vision 🚀

## 💾 Example files

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/973892292868502990>" %}


# Pages


# Modal pages

Pages that slides in from the bottom and covers the screen.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag, placed on a top-level app page, creates a page that slides in from the bottom and covers the  screen.

**📍 Where to add the tag:** A top-level app page

![](/files/MthOMvdR1ewtAb1BC99Q)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a Modal page design.
2. Use the tag that you prefer the most for modal page.

## Types of modal pages

### Page modal 100%

This modal will always be 100% of the mobile screen and this is a fix modal. Use this tag:

```
[page:modal]
```

![](/files/tpS6W9Irx2b6PPdRqSe8)

### Page modal % Size

Define the percentage number of the screen that your modal will shown up. Could be scrollable! Make it as long as you want. Several samples here:

```
Size 30% [page:modal:30%] 
Size 50% [page:modal:50%]
Size 70% [page:modal:70%]
Size 90% [page:modal:90%]
```

![](/files/SeGx119ca8l96nEby3cf)

### Page Modal Fixed Size

Add the following tag in case you want the modal to be fixed:

```
Page Fixed [page:modal:fixed]
```

![](/files/ZxHdrDI1nZDUmkB1XYK9)

### iOs Cards Modal Type

This type of Modals are just working in iOs. This will be a 100% screen modal and scrollable! Add this tag:

```
iOs cards [page:modal][ios:cards]
```

![](/files/dNe0ATZlrRpRwn0xdItU)

{% hint style="info" %}
🔥 Important: Noticed that for the experience you will close them with a swipe down.
{% endhint %}

Now you can do the prototyping! Import to Bravo & preview on Bravo Vision 🚀

![](/files/mEbN2JQqNF0XLwsMxvkz)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/967380255651810770/bravo-sample-modal-pages>" %}


# Pop-up pages

Pop-up pages can be effective for drawing attention to specific information or encouraging user interaction.

## 👉 **The Tag**

By using this new tags you will be available to make new pages to popup!

**📍 Where to add the tag:** A top-level app page.

![](/files/Hiq7s7xpaDOY0xeuYwfe)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a Pop up design.
2. Use the tag that you prefer the most for your pop-up.

### Normal Pop Up

Use this tag:

```
Normal Popup [page:popup]
```

![](/files/9H2liWe9LVFpYA1ML7QV)

### Rounded Corners Pop Up

In case you want rounded corners use this tag:

```
Rounded Corners Popup [page:popup] 
```

![](/files/K12uRbTBvNKS82NJPIRY)

### Color Background Pop Up

In case you want a color background Pop up use the follow tag:

```
Color Background Popup [page:popup:#CCFAFF00]
```

![](/files/rgCq0V8b5uMFZ2IeuRpd)

### Blur Background Pop Up

You want a blur background Pop Up:

```
Blur Background Popup [page:popup:blur] 
```

<figure><img src="/files/YovOoQfSv5ajxu2uhJdt" alt=""><figcaption></figcaption></figure>

### Slider Pop Up

This is the case if you need to show more than one pop-up at a time.

```
Slider popup[page:popup]
Slide [container:slider:horizontal]
```

![](/files/vREBeBlWxVGllxXE2aXM)

{% hint style="warning" %}
🔥 Important: To Close the popup the action close will be required:

\[action:close]
{% endhint %}

Now you can do the prototyping! Your Pop Up is ready to use. Import to Bravo & preview on Bravo Vision 🚀

<figure><img src="/files/i54F90MTHimt9IpDqk8D" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
it's important to use the Pop up pages judiciously to avoid creating a negative user experience, as excessive or intrusive pop ups can be disruptive and may lead to a poor user experience.
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% @figma/embed fileId="nC316U8ydYtNBa3bhKe2jz" url="<https://www.figma.com/file/nC316U8ydYtNBa3bhKe2jz/Bravo-Sample%3A-Pop-ups-(Community)?mode=design&t=2NP3UHI8QVRQ6cpm-0&type=design>" %}


# Swipe page

Add a component with a vertical swipe effect

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Creates a horizontal or vertical **swipe component**, which occupies the whole app screen. The list of elements in the component can be created in the design file, or created dynamically with [API data](/data-binding/data-binding-types).

**📍 Where to add the tag:** A top-level app page.

```
[page-swipe:vertical] -> vertical slide effect
[page-swipe:horizontal] -> horizontal slide effect
```

![](/files/NMbRVcaoTbMFQ0kbkqvY)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1\. Create a screen design for the vertical swipe. Add the `[page-swipe:vertical]` or `[page-swipe:horizontal]` tag to the top-level app screen component.

![](/files/3qcZtZotn8JitmDuZ8CM)

<figure><img src="/files/1GT5Ti13H784aNDnp2H3" alt=""><figcaption></figcaption></figure>

2\. Create a single `[container]` element covering the whole screen and wrapping all the individual UI elements of the swipe component (images, texts...). Add the [`[aspectratio:screen]`](/bravo-tags/containers/aspect-ratio-relative-to-screen) tag to the container, to avoid undesired scrollings in devices with smaller screens.

![](/files/GEQyGxfrWebnOOoZahU6)

3\. If you want to have a **static list** (created in the design file) for the swipe component, create several containers with the corresponding UI elements, and put them one on top of another.

4\. If you want to **populate the list dynamically with API data**, create a single container with all the UI elements that will be bound to data. Then, in the [data binding](/data-binding/data-binding-types) section, bind the container and the UI elements to the corresponding list data items.

## 🎨 Example design file

{% embed url="<https://www.figma.com/community/file/1125815853125858367>" %}


# Transitions page

Transitions are used to create a smooth and visually appealing flow between different views or states of an app, enhancing the overall user experience.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Add a tag to set up a specific transition to open an app page.

**📍 Where to add the tag:** This tag should be located at Page level  (Top-level Figma Frame)

![](/files/1bSyFgFR5qlFg6AA4Nis)

## 🏷️ Transition Types

### Slide&#x20;

Use this tag:

```
[transition:slide:left]
[transition:slide:right]
[transition:slide:up]
[transition:slide:down]
```

<figure><img src="/files/ZmXBLWHr57R5YqdKNqdb" alt=""><figcaption></figcaption></figure>

### Move&#x20;

Use this tag:

```
[transition:move:left]
[transition:move:right]
[transition:move:up]
[transition:move:down]
```

<figure><img src="/files/gtNmm445IL5zlaYIOlTv" alt=""><figcaption></figcaption></figure>

### Push <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

Use this tag:

```
[transition:push:left]
[transition:push:right]
[transition:push:up]
[transition:push:down]
```

<figure><img src="/files/T0PLX8ju0iXGCXrHCsXm" alt=""><figcaption></figcaption></figure>

### Instant  <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

Use this tag:

```
[transition:instant]
```

<figure><img src="/files/hjnIPEBKW6gXdrEmYZ3D" alt=""><figcaption></figcaption></figure>

### Dissolve  <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

Use this tag:

```
[transition:dissolve]
```

<figure><img src="/files/4IacY0FR5Hj1YUWfsvuv" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/G1sZitRwDzDckFde6A1W" alt=""><figcaption></figcaption></figure>

Now you can do the prototyping! Your transition page is ready to use. Import to Bravo & preview on Bravo Vision 🚀

<figure><img src="/files/5VI0cP7inS9RovK7k6Ag" alt=""><figcaption></figcaption></figure>

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981975323423403527>" %}


# Page reveal animations

Refers to an animated effect where content or elements gradually become visible on the screen, often in response to a user interaction.

## 👉 **The Tag**

Add a tag to set up a specific transition to open an app page.

**📍 Where to add the tag:** A top-level app page.

![](/files/4AJRLPX2NSWY0I32yLFO)

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. On a blank app page, create a Reveal animation design.
2. Use the tag that you prefer the most for your reveal animation.

### Contract

Use this tag:

```
[animation:contract:light]
[animation:contract:medium]
[animation:contract:heavy]
```

![](/files/QN9fSL3d0vN1jUInlOdC)

### Fade in&#x20;

Use this tag:

```
[animation:fadein:light]
[animation:fadein:medium]
[animation:fadein:heavy]
```

![](/files/poTnd34Q8jqe7PW9VCQe)

### Spin&#x20;

Use the follow tag:

```
[animation:spin:light]
[animation:spin:medium]
[animation:spin:heavy]
```

![](/files/6SBncMLIWTn7VvfjNbvw)

### Expand&#x20;

Use this tag:

```
[animation:expand:light]
[animation:expand:medium]
[animation:expand:heavy]
```

<figure><img src="/files/leXYmLJZvbAgoWwjKYwv" alt=""><figcaption></figcaption></figure>

### Slide left&#x20;

Use this tag:

```
[animation:slideleft:light]
[animation:slideleft:medium]
[animation:slideleft:heavy]
```

![](/files/Ys2sZZxbuc5ZjgwtXHrV)

### Slide right&#x20;

Use this tag:

```
[animation:slideright:light]
[animation:slideright:medium]
[animation:slideright:heavy]
```

<figure><img src="/files/XAsRcMPkmVHrn42BZ8Az" alt=""><figcaption></figcaption></figure>

### Slide top&#x20;

Use this tag:

```
[animation:slidetop:light]
[animation:slidetop:medium]
[animation:slidetop:heavy]
```

<figure><img src="/files/htyT9ztPWBQxRRFJoJxp" alt=""><figcaption></figcaption></figure>

### Slide bottom&#x20;

Use this tag:

```
[animation:slidebottom:light]
[animation:slidebottom:medium]
[animation:slidebottom:heavy]
```

<figure><img src="/files/r2rOFd8349LAd2BjAIdU" alt=""><figcaption></figcaption></figure>

Now you can do the prototyping! Your reveal animation is ready to use. Import to Bravo & preview on Bravo Vision 🚀

<figure><img src="/files/17RmGstLgwuH0uTKr2iM" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Designers and developers use various techniques and frameworks to implement reveal animations, ensuring they contribute positively to the overall user experience.
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/938435282064183751/bravo-sample-page-reveal-animations>" %}


# Page tabs

Add a screen with tabs displaying different content

Toggle content inside a page without needing to replicate screens. Page tabs can be used either as an extra navigational hierarchy that complements the main bottom menu or you can also use it to navigate content with buttons inside a page.

<figure><img src="/files/FypDXeRir9r9i5mlBNKk" alt=""><figcaption></figcaption></figure>

## 👉 **The Tags**

This component requires the following tags:

* <mark style="color:red;">**`[container:tabs]`**</mark>: this tag creates a special [container](/set-up-design/setting-up-your-design-file/the-container) element, wrapping up both the tabs control and the content of the segmented tabs. It needs to be added in the [**2nd level laye**](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy)**r** in the design file and its size shouldn't be bigger than the main screen.
* <mark style="color:red;">**`[container:tabs-controls]`**</mark>: a special container inside the <mark style="color:red;">`[container:tabs]`</mark> element. It will contain the tabs controller to switch between the different segmented tabs. It needs to be aded in the [**3rd level layer**](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy) in the design file.
* <mark style="color:red;">**`[container:tabs-content]`**</mark>: a special container inside the \[container:tabs] element. It will be used for the content for the segmented tabs. It needs to be aded in the [**3rd level layer**](/set-up-design/setting-up-your-design-file/structuring-the-design-the-layer-hierarchy) in the design file.

## 🎨 Design setup

1. Create the tabs controller, using a [stateful component](/bravo-tags/components/stateful-component-like-button) to create the buttons and different states (default and active). Create a <mark style="color:red;">`[container:tabs-controls]`</mark> around the buttons.
2. Create a frame that takes the space for the segmented tabs content. Add the <mark style="color:red;">`[container:tabs-content]`</mark> tag in this element.
3. Surround all these elements with a <mark style="color:red;">`[container:tabs]`</mark> element, located in the second-level layer.

<figure><img src="/files/yCrEl1gaOo2npqUnTel8" alt=""><figcaption></figcaption></figure>

4\. Finally, to create the content for the segmented tabs, create separate screens with the content you want to display, and create prototyping links from the buttons in the controller to these pages. You can [bind API data](/data-binding/data-binding-types) to the pages as well.

<figure><img src="/files/XUjFe2PBiwvlIKifSx44" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Please note that the `refresh:pull` tag is currently not supported within a Tabs Container on Android devices.
{% endhint %}

## 💾 Example file

Duplicate this file below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1182258624876265324>" %}


# Stateful pages

In our system, there are three stateful pages: the **default state page**, the [**empty state page**](#empty-state-page), and the [**error state page**](#error-state-page). In this guide, we will walk you through the process of creating the latter two.

## Empty state page

The empty state page shows a special page when no data is available.

To implement this, it is necessary to create a special page that will be displayed **when a list bound to another page is empty**. The setup will consist on the following two tags, one for each of the pages involved.&#x20;

* <mark style="color:red;">`[state:default:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark>: this tag will be added in the top-level element of the **page with API list data bound to it**.
* <mark style="color:red;">`[state:empty:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark>: this tag will be added in the top-level element of the **page that will be displayed if the list connected to the previous screen is empty**.

Replace *<mark style="color:green;">groupname</mark>* with any name of your choice that identifies the group of those two pages.

{% hint style="warning" %}
Please note that for this screen to be displayed, the API must return an **empty list** and it supports a unique API request in the same page.
{% endhint %}

<figure><img src="/files/tTobKQvz1xffFnfeZQ0M" alt=""><figcaption></figcaption></figure>

## Error state page

Create a special page that will be displayed **when an API error happens** in a specific app page.

By default, Bravo will show a generic error page (including the [HTTP error code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)) when an API error happens. With this error page, you can customize this error page, and connect it to an app screen returning data from API, so when an API error happens, this custom error page is displayed.&#x20;

There are two options to set it up:

* **Error state pages**: Add <mark style="color:red;">`[state:error:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark> in the page-level to create an error page that will be displayed **when any API error happens** (4XX or 5XX).
* **API Error code page**: Add <mark style="color:red;">`[state:error-XXX:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark> in the page-level to create an error page that will be displayed **when a specific API error happens**, replacing XXX with the corresponding error code. For instance, <mark style="color:red;">`[state:error-404:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark>.

Then, relate the error page to a page bound to API data. This page needs to have the <mark style="color:red;">`[state:default:`</mark>*<mark style="color:green;">`groupname`</mark>*<mark style="color:red;">`]`</mark> tag. *<mark style="color:green;">groupname</mark>* should be replaced with a name of your choice, that creates the relationship between the two pages.

{% hint style="warning" %}
Pages with error state tags are special and have some limitations:\
\
\- It's not possible to combine other tags with error stage tags.\
\- It's not possible to bind data in pages with error state tags.
{% endhint %}

{% hint style="warning" %}
Error state and Empty pages can be only applied to **Content binding**. Can be used with [Backend Search](/get-started/help-and-tutorials/browse-by-app-feature/backend-search-with-airtable) but not compatible with [Search & Filter](/bravo-tags/mobile-actions/component-search-and-filter).
{% endhint %}

{% hint style="info" %}
Additionally, we recommend using these tags for a better UX experience:

<mark style="color:red;">`[refresh:pull][refresh:always]`</mark>
{% endhint %}

## 💾 Example file <a href="#example-files" id="example-files"></a>

Duplicate the file below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1385223397256185027>" %}


# Containers


# Swipe to delete

Enable a native swipe-to-delete functionality in your app

{% hint style="info" %}
[Upgrade your free account](/get-started/unlock-power-features-to-create-interactive-apps) to the **Bravo Solo plan** to use this feature.
{% endhint %}

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Enables a swipe-to-delete gesture for items in a list. The tag will be applied to the item container and it needs to be bound to an API request that deletes the item on the backend. When the user swipes the item, it is removed from the screen and the API request is triggered.

{% hint style="success" %}
On **Android**, when swiping an item, it will be automatically removed from the screen. On **iOS** the user will need to press on a “**delete**” button to confirm the action.
{% endhint %}

**📍 Where to add the tag**: A container element.

![](/files/J7IJcT1ZlnQWRLPUZok8)

## 🏷️ **How to set it up** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. Add the `[swipetodelete]` tag to the list container where we want to enable the swipe-to-delete gesture.

![](/files/MfWEi4EvBGYodTWjuI1h)

The tag enables three properties that need to be bound:

* **Container**. To show the list of items and activate the gesture on each of them.
* **Sort/Swipe to delete ID**. To indicate the ID of each item.
* **Remote action (swipe to delete)**. To indicate the API request that performs the deletion on the backend.

You can skip the Visibility property.

2\. Bind the **Container property** to an API request returning a list of items. The list container can have as many UI elements inside as you wish. \
In our example, we have bound the "**Contacts - List"** request with the "**records"** object, which contain the list of items:

Make sure the API request returns a **unique ID** for each record, and that it is selected (it appears in the Selected Data tab). This variable will be used later for the delete action.

3\. Open the "**Sort / Swipe to delete ID**" property and select the unique ID mentioned on step 2.

![](/files/5oZnFMPhtOofVJX9O0Fg)

4\. Create an API request that deletes the record from your backend. This request needs to receive the unique ID from step 3 as a param. Make sure the variable name is the same on both requests (in our case, "id") and it is set as `${id}`, wrapped up in with the dollar and brackets:

5\. Go back to the binding screen and open the **Remote action (swipe to delete)** property and select the delete API request. It will be triggered when the users perform the swipe gesture. You can also assign On Success and On Error actions.

![](/files/QrPMoFkmqu3Pfa0gpMq7)

6\. Ready to go! Now your list items will be deletable with a swipe gesture.

## 💾 Example file <a href="#example-files" id="example-files"></a>

Duplicate the example design file below to get started!

{% embed url="<https://www.figma.com/community/file/1140972531178104786>" %}


# Top bar

The top bar container fixes its position to the top of the screen and does not scroll with the rest of the screen.

{% embed url="<https://www.youtube.com/watch?v=-Ijh3AiiAm0>" %}

## :point\_right:The tags

The top bar container fixes its position to the top of the screen and does not scroll with the rest of the screen. There are 3 different types of top bars:

1. **Fixed Top Bar:** This will be always visible.

<mark style="color:red;">`[container:top-bar]`</mark>

2. **Show Top Bar:** This will show when you scroll.

<mark style="color:red;">`[container:top-bar:showscroll]`</mark>

3. **Hide Top Bar:** This will hide when you scroll.&#x20;

<mark style="color:red;">`[container:top-bar:hidescroll]`</mark>

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. Create a container around the section of the app page that you want to stay fixed.

{% hint style="info" %}
Make sure all the side of the container touches the edges of the app page or other containers.
{% endhint %}

&#x20;   2\. **Copy & paste** the tag into the layer name of this **container**

![](/files/OYYENN1bZIpkLSiAdzuH)

&#x20;   3\. Import to Bravo Studio & preview on Bravo Vision 🚀 (If you imported the app before, you just need to press the button Update in Bravo Studio to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981972505586768390>" %}


# Carousel slider

Slides a collection of containers horizontally.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Slides a collection of containers horizontally. The slider can have different animations, depending on the tag placed (see section below).

**📍 Where to add the tag:** A second-level container

![](/files/-MflwVsZqRxBIJfuJQnP)

## 🏷️ Animation Tags

Each tag is a different animation. In the tabs below you can discover all of them!

{% tabs %}
{% tab title="Default" %}

```
[container:slider:default]
```

![](/files/-MfmtcDaX5FCHhLViKky)
{% endtab %}

{% tab title="Crossfade" %}

```
[container:slider:crossfade]
```

![](/files/-MfmuICslTVjcPQaThcd)
{% endtab %}

{% tab title="Cube" %}

```
[container:slider:cube]
```

![](/files/-Mfmw5zRzLqWB1SX4yGq)
{% endtab %}

{% tab title="Pager" %}

```
[container:slider:pager]
```

![](/files/-MfmwCMDm14-BmN-jEAv)
{% endtab %}

{% tab title="Parallax" %}

```
[container:slider:parallax]
```

![](/files/-MfmwGuWkHDSYohxGA4W)
{% endtab %}

{% tab title="Rotate" %}

```
[container:slider:rotate]
```

![](/files/-MfmwLd1jTGF14XuY4Rj)
{% endtab %}

{% tab title="Zoom" %}

```
[container:slider:zoom]
```

![](/files/-MfmwQMtPAGd3YJ-OuQ8)
{% endtab %}

{% tab title="Horizontal" %}

```
[container:slider:horizontal]
```

![](/files/-MfmwVuomkxrfb7zSm0R)
{% endtab %}
{% endtabs %}

## 🏷️ Optional Tags

You can add as many of these tags as you want to the slider container.

{% tabs %}
{% tab title="Slider Indicator" %}

```
[slider-indicator:#FFFFFFFF]
```

```
[slider-indicator:<active_color>:<inactive_color>]
```

![](/files/-Mfmxc1PLw9Ruqd1v_x4)

Adds a dots indicator at the bottom of the slide container, with the specified color (use 8-digit HEX code - alpha included). \
\
You can also specify a color for the active item and another color for the inactive ones.

**📍 Where to add the tag:** on the same layer as the <mark style="color:red;">`[container:slider]`</mark> tag.\
\
For example \[slider-indicator:] needs to be:

\[slider-indicator:#FFFF0000:#FF00FF00]. \
For #FF0000 and #00FF00, we add FF at the beginning to set alpha at 1 (no transparency).

{% hint style="warning" %}
This tag is supported for all slider animations except for <mark style="color:red;">`[container:slider:horizontal]`</mark>.
{% endhint %}
{% endtab %}

{% tab title="Infinite slide" %}

```
[slider-infinite]
```

![](/files/-Mfmy5E-1V21iEGNM9oD)

After the last slide, the first slide will be shown, so user can swipe in one direction infinitely.

**📍 Where to add the tag:** on the same layer as the <mark style="color:red;">`[container:slider]`</mark> tag.
{% endtab %}

{% tab title="Automatic slide" %}

```
[slider-automatic:<time-in-seconds>]
```

Slider will move automatically **every x seconds**.

For example: 8 seconds <mark style="color:red;">`[slider-automatic:8]`</mark>

**📍 Where to add the tag:** on the same layer as the <mark style="color:red;">`[container:slider]`</mark> tag.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can also add the tags <mark style="color:red;">`[action:prev-slide]`</mark>and <mark style="color:red;">\[action:next-slide]</mark> to any design element (i.e. buttons) for easy navigation between slides.
{% endhint %}

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. Create a slide design with your slides lined up next to each other horizontally, with each "slide" in its separate container. If you want to connect your slider to a list of data from API, see **step 5**.

{% hint style="info" %}
Only the <mark style="color:red;">`[container:slider:horizontal]`</mark> (i.e. horizontal scroll) allows for slides that are smaller than the width of the screen. All other slide effects must have individual slides that stretches the full width of the screen.
{% endhint %}

![If your design has slides smaller than the width of the screen, use \[container:slider:horizontal\]. ](/files/-Mg5G4l_1pJTO7Ky-YKy)

2\. **Create a container around the slider design** that contains all of your slides and is the full width of the screen. Similar to how you set up overflow behaviour for Figma prototype.

![Container setup for slides the full width of the app screen.](/files/-Mg5Ggx3sQY0A2MSio1_)

![Container setup for slides smaller than the width of the app screen.](/files/-Mg5GpIWe3TlvF61xlFN)

3\. Paste the slide animation Tag of your choice to the layer name of this container.

![](/files/-Mg5HNR38KhSwLv7_61S)

4\. Import to Bravo & preview on Bravo Vision 🚀

5\. If you want to connect API data to your slider, you only need to create the first slide as a placeholder design.

![](/files/-Mg5I2RqnemftqYC5eLs)

6\. Then connect your list of data the same way you would with a vertical scrolling list ([tutorial here](/data-binding/display-data-in-your-app/data-biding-bind-data-to-ui-for-a-list-page)). However, you need to connect the data array to the **individual slide element**, rather than the slider container.

![Connect the list request to the "Container" property of the slide element highlighted in blue.](https://s3.eu-central-1.amazonaws.com/trengo/media/inline_image_72445_mBlRrkJzcKWYqSZRUmkc0UQZd7zAA8bkCNMETyLt_1652180692131.1652180692131.png)

7\. If you want each slide to open another page, make sure you link the individual slide element to the other page.

![](/files/-Mg5MZHAWWPjUPfKqaqK)

8\. Preview on Bravo Vision 🚀

{% hint style="danger" %}
You cannot use the \[flexo] tag in a slider, as all slides need to have the same fixed size.
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/982167580060315188>" %}

{% file src="/files/-Mg5PeS1hM5OzUeo4glv" %}
Bravo Sample - Horizontal Sliders.xd
{% endfile %}


# Aspect ratio relative to screen

The height of the container is calculated with the screen height.

<figure><img src="/files/nZfEhPysd8AXfwncECG0" alt=""><figcaption></figcaption></figure>

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

The height of the container is calculated with the screen height, so they won't maintain the designed aspect ratio, but is useful when you want a container to be relative to the screen. (ex: container height is 100% of the screen in the design, it will appear 100% on any device screen).

**📍 Where to add the tag:** A second-level container

```
[aspectratio:screen]
```

![](/files/AVIxwq9VnPt8cYU8k8bt)

**How does it adjust your design to fit to any phone?**

Bravo renders components considering their dimensions in reference to the specific device dimensions. In other words, it uses percentages to adapt to each screen.

{% hint style="info" %}
If the design is not fitting the screen as intended, add a [splash screen](/bravo-tags/app-icon-and-splash-screen) in your Figma. The splash screen acts as a "default" size for Bravo to calculate the ratio of the other app pages.
{% endhint %}

## 🏷️  **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. Create your design on the default app page size.

&#x20;   2\. Add a container around the design.

&#x20;   3\. **Paste** the tag into the layer name of the **2nd-level container.**

![](/files/yqeq4VzrbVe5yIeE4TyY)

<figure><img src="/files/gTZyihnDcnY2njYb2N7E" alt=""><figcaption></figcaption></figure>

&#x20;   4\. Import to Bravo Studio & preview on Bravo Vision 🚀 (If you imported the app before, you just need to press the button Update in Bravo Studio to see the changes).

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1362739745744253923>" %}


# Sortable List

Creates a sortable list with API data

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Drag and drop your list items and change their order! Create a sortable list to enable this behavior in a list inside your app.

**📍 Where to add the tag**: A container element.

```
[sortable]
```

## ⚙️ Backend setup

In order to sync the list reordering in the backend, the API endpoint needs to receive an API request every time a user changes the order of the items. Therefore, some backend logic is needed to update the database accordingly.&#x20;

To get started quickly, we created a Xano snippet that will generate the API endpoints needed to handle the reordering, together with a database with some sample data. We recommend [installing it in your Xano environment](https://docs.xano.com/xano-features/snippets/preview-and-add-a-snippet). You can also develop your own backend from scratch (you'll need this in case you're using a different tool). Note that this will require some advanced technical skills.

{% embed url="<https://www.xano.com/snippet/KSMaDRAi>" %}
Xano snippet
{% endembed %}

## 🎨 Design setup

Add the `[sortable]` tag in the corresponding container element. When connecting the container to API data, a sortable list will be created in the app.

<figure><img src="/files/EWZ6mFcPoUDceXh6YgUb" alt=""><figcaption></figcaption></figure>

We created a sample design you can check out. Feel free to duplicate and customize it.

{% embed url="<https://www.figma.com/community/file/1151548231007345327>" %}

## ⚒️ API requests setup

In order for this feature to work, we’ll need (at least) the following API requests:

* A `GET` request to obtain the corresponding list data.
* A `PUT/PATCH` request that will be triggered whenever a user reorders the list. This request will send the necessary information so the list is reordered in the backend.

### <mark style="color:orange;">`PUT`</mark> request

**In case you use our Xano snippet**, you’ll need to setup the PUT request in the way explained below.

**Request URL**

It will be the one that communicates with the corresponding `PUT` endpoint in the backend. In this example, the `${tasks_id}` variable will take the value of the record ID, so you’ll need to use this name in the GET request’s Selected Data section for the record ID data.&#x20;

Note that you can use a different variable name, as long as the names in Selected Data and in the PUT request URL match.

```
https://XANO_SERVER_URL/API_GROUP_URL/tasks/${tasks_id}/position
```

**Request body**

Use the following request JSON body to target the Xano endpoint.

{% hint style="info" %}
`${movedAfterItemId?}` is a special variable that will contain the ID of the list item that is located above the position of the reordered item. For example, in case an item is moved to the second position of the list, `${movedAfterItemId?}` will contain the ID of the item in the first position.
{% endhint %}

```
{
  "previous_tasks_id": "${movedAfterItemId?}"
}
```

### <mark style="color:green;">`GET`</mark> request

Finally, you'll need a [GET request to obtain the data for the list items](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/set-up-an-api-get-request-for-list-page-airtable). Remember to select the ID of the list items, and give it the same name as the variable in the PUT request URL.

## **🔌** Data binding setup

Once the API requests are created, it’s time to bind the properties of the sortable list to the corresponding data items. Bind the following properties as shown below.

**Container**

Bind this property to the list data item that references the API list.

<figure><img src="/files/qJEid6vpOk18IAyFSp6W" alt=""><figcaption></figcaption></figure>

**Sort / Swipe to delete ID**

Bind this property to the data item that references the list record ID. It should be in the same request that was bound to the `Container` property.

<figure><img src="/files/3lg9sqp0KmKHYT7sDAoJ" alt=""><figcaption></figcaption></figure>

**Remote action (sort)**

Bind this property to the request that is triggered upon list reordering. In case you use our Xano snippet, this will be the PUT request created previously. Choose `No action` for the `On Success` / `On error` actions, unless you want to implement a different behavior.

<figure><img src="/files/zIF6JleyvnKNDT5qk7ET" alt=""><figcaption></figcaption></figure>

## 📲 Test in Bravo Vision

That’s it! Open your app in Bravo Vision to test the sortable list. The sortable list works by long pressing an item in the list and dragging it to a new position.


# Layer (sticky element)

A container that fixes its position on-screen and does not scroll with the rest of the screen.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag creates an element that fixes its position on-screen and does not scroll with the rest of the screen.

**📍 Where to add the tag:** A second-level container.

```
[layer]
```

{% hint style="warning" %}
Layers are positioned considering the full screen dimensions. They are not supported in modals and pop ups.&#x20;
{% endhint %}

![](/files/-Mg5QLVocVaNmZ8FCF2p)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. Create your layer element design.

![](/files/-Mg5S2boSocBMArlBYpG)

2\. **Wrap it in a container.** Unlike normal containers, layer elements don't need to be the full width of the screen.

{% hint style="warning" %}
Make sure it's not inside another container. It should be a 2nd-level layer.
{% endhint %}

![](/files/-Mg5TAHeTjmMaouLmq5n)

3\. **Paste** the tag into the layer name of this container.

![](/files/-Mg5TZ_0AzlQ0JCzLZzn)

4\. **Place it in the desired position** where you want it to stay fixed in the "default screen area." The default screen area is one app page at 100%. **If you have a splash screen in your design file, Bravo will use it as the default screen size**. If you place the layer element outside of this area (for example on a long page), it will not appear.

![For ex: I want the blue button to stick at the bottom of the screen, but instead of placing it at the bottom of my actual design, I place it near where the device screen would cut off.](/files/-Mg5TrF61eiTZ3oK4cpu)

5\. Make sure the layer is not inside another container. It should be its own 2nd-level frame.

![](/files/-Mg5U-sbr6IfSXa4B1Od)

6\. Import to Bravo & preview on Bravo Vision 🚀

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/973892292868502990>" %}

{% file src="/files/-Mg5UHAwVF7HJJ9IivHt" %}
Bravo Sample - Sticky Layer.xd
{% endfile %}


# Intro & Onboarding


# Intro page

Displays an Intro screen of your choice.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Displays a custom intro screen either 1) every time the app user opens the app or 2) only the first time.

**📍 Where to add the tag:** A top-level app page

```
[intro:always] or [intro:once]

//Add this tag in a visual element (NOT a top-level app page) to close the intro screen.

[action:closeintro]
```

{% hint style="info" %}
`[intro:always]` displays the intro **every time** the user opens the app.\
`[intro:once]` displays the intro **only the first time** the user opens the app.
{% endhint %}

![](/files/-Mhsa0glkeVvlxrepE1O)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   1\. Create an intro screen design.

{% hint style="info" %}
**Pro tip:** use the [Lottie component](/bravo-tags/components/component-lottie) to easily add a Lottie animation in your intro.
{% endhint %}

![](/files/-Mhsboav9SwweqOBJ4Xq)

&#x20;   2\. Add a container around the design.

![](/files/-MhsbsjnyW8Upw1T9kBH)

&#x20;   3\. **Paste** the tag `[intro:always]` or `[intro:once]` into the layer name of the **top-level app page**.

![](/files/-MhsbyM-fAFa-W4ctIut)

&#x20;   4\. **Paste** the tag `[action:closeintro]` into the layer name of a **visual element** to close the intro screen.

![](/files/-Mhsc1iFDfc-3oIArtNV)

&#x20;   5\. Make sure the **Starting Frame** is on your "home" app page, not the intro screen. Also make sure **there is** a Starting Frame.

{% hint style="danger" %}
Don't link the intro page to any screen. It's a standalone screen. The **close intro Tag** will automatically reveal the **Starting Frame** screen.
{% endhint %}

{% hint style="warning" %}
You can create an intro flow with several screens. If you do this, **do not** link the last page of the intro with the first page of the app, but add an `[action:closeintro]`  element. Check how it's done in the example design files.
{% endhint %}

![](/files/-MhscC2n_FR-rAb9J86-)

&#x20;   6\. Import to Bravo & preview on **Bravo Vision** 🚀

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981964292540895745>" %}

{% file src="/files/-MhsdlE3L20BmdsO-uSz" %}
Bravo Sample: Intro Pages.xd
{% endfile %}


# Post-login page (Onboarding)

Add a page that will be displayed after a user logs in or registers

{% hint style="info" %}
Some examples of what you can do using this tag:

* Show a form to complete the user’s profile after signing up
* Show a page to ask for notification permissions
* Show a one-time welcome screen
  {% endhint %}

{% hint style="warning" %}
This tag is **supported for Firebase and Custom Backend** email/password authentication
{% endhint %}

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Displays a post-login screen after a login or register action. It will be displayed **after** the login or register action, and **before** the home screen.

This tag will allow you to show a permanent screen after a user logs in and before they navigate to the home, or create an onboarding for first-time users.

There are two different ways to add this tag:

**a)** Control with different tags whether we want to show the post-login page only upon user registration, or every time users log in.&#x20;

**b)** Control from the backend when to show the post-login flow to each user. This method requires advanced backend setup, where the backend returns either a success or an error HTTP code, which controls the post-login visibility.

These two setups are detailed below.

## **Control visibility of the post-login with tags** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

This setup allows to control whether the post-login page will be displayed after a user registers (first-time login), or every time a user logs in.&#x20;

{% hint style="danger" %}
To ensure this working with [Authentication with Custom Backend](https://docs.bravostudio.app/integrations/user-authentication/authentication-with-custom-backend), the Sign up page should automatically log in the user to the app. This can be achieved by using<mark style="color:red;">`[action:register]`</mark>tag in the Sign in button and using **Set Access Token** as form response action. Detailed instructions on how to set this up can be found [here](https://docs.bravostudio.app/integrations/user-authentication/authentication-with-custom-backend#signup-screen).
{% endhint %}

{% hint style="info" %}
It's recommended for MVPs or prototypes with a limited user base, specifically those using email-based authentication. Otherwise, we recommend using the [setup shown in the next section](#example-files).
{% endhint %}

1. Create a post-login page design.

![](/files/R3gRN8mYSGfbxDsaKquY)

2\. Add a container around the design.

![](/files/2FX8OjAgBr0SA6hs0Bjc)

3\. **Paste** the tag <mark style="color:red;">`[post-login:always]`</mark> or <mark style="color:red;">`[post-login:once]`</mark> into the component name of the **top-level app page**, depending on the behaviour you want to implement.

![](/files/s3c9zrDnBv4NScmldYd7)

4\. **Paste** the tag <mark style="color:red;">`[action:close]`</mark> into the component name of a **visual element** to close the post-login screen and navigate to the home page. Make sure you've specified the [start of the prototyping flow](/get-started/your-bravo-app-projects) in the Home screen.

![](/files/IuvirFHxahMT1KyrRmsH)

You can duplicate the example file below to get started:

{% embed url="<https://www.figma.com/community/file/1101496157843308166>" %}

## Control visibility of the post-login from the backend <a href="#example-files" id="example-files"></a>

This method offers a more robust approach and supports all the authentication methods provided by Bravo. It involves implementing a conditional logic in the backend to determine whether the post-login screen should be displayed. It could return either a success or an error code depending on the desired behaviour to show or skip the post-login flow.

1. Add the <mark style="color:red;">`[post-login:action]`</mark> tag to the screen to the screen with the <mark style="color:red;">`[page:login]`</mark> tag. This will enable the possibility to bind an API request to the login action.

![](/files/liRhOZwDCoxW506Gpsac)

2. &#x20;Add the <mark style="color:red;">`[post-login]`</mark> tag to the post-login screen or to the start of the post-login flow if there are several screens connected.

![](/files/IMmFKMoF449N4MTESD8e)

3. Set up an API endpoint in your backend that returns an **HTTP success code (2XX)** to show the post-login screen, or an **error code (4XX)** to skip it (or the other way around). This implementation is backend-specific and requires integration with your chosen tool or technology.&#x20;
4. Create an API request in Bravo with the post-login endpoint. **This request will be triggered when a user executes the login action.**
5. In the Data Binding section for the login page, you'll be able to bind an API request and <mark style="color:red;">`On Success`</mark> <mark style="color:red;"></mark><mark style="color:red;">/</mark> <mark style="color:red;"></mark><mark style="color:red;">`On Error`</mark> response actions. Select the API request that communicates with the endpoint you created in the previous step. Then, choose whether you want to skip or show the post-login flow if the request returns a success code <mark style="color:green;">`On Success`</mark>, and choose the other option for the <mark style="color:red;">`On Error`</mark>.

![](/files/hmBu9hUPbQc1j2UX9ZpE)

5\. That's it! You can now test your post-login flow.


# Loading experience


# Loading page

The app page will display in place of the default Bravo loading screen.

The screen with this tag replaces the default Bravo loading screen with a custom design app page.

**📍 Where to add the tag:** A top-level app page

```
[state:loading]
```

<figure><img src="/files/DvWrqjd4GscgCGu6ToJj" alt=""><figcaption></figcaption></figure>

![](/files/-MhwnR031h5y_0ZnLrx1)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   1\. Create a standalone loading screen design.

{% hint style="info" %}
**Pro tip:** use the [Lottie component](/bravo-tags/components/component-lottie) to easily add a Lottie animation in your intro.
{% endhint %}

![](/files/-Mhwo1DaBu5ehqwhI1rM)

&#x20;   2\. Add a container around the design.

![](/files/-Mhwo5lerb3OhFXaDv41)

&#x20;   3\. **Paste** the tag into the layer name of the **top-level app page**.

![](/files/-MhwoAhpTaGjhdRRTjkW)

&#x20;   4.Import the design file into Bravo.

&#x20;   5\. Set up your [binding](broken://pages/-Mflj2uo5W_jthsMwnSm) as usual.

&#x20;   6\. Preview the custom loading screen on Bravo Vision. 🚀

{% hint style="info" %}
Tip: If you want to show the loading animation on top of the screen that is being loaded, add a **transparent background** to the screen with the `[state:loading]` tag.
{% endhint %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/973892292868502990>" %}

{% @figma/embed fileId="dedkxpF23DnniDkjZnqehd" nodeId="453:36" url="<https://www.figma.com/file/dedkxpF23DnniDkjZnqehd/Bravo-Sample%3A-Bravo-Tags?node-id=453%3A36>" %}

{% file src="/files/-MhwogYPw9o4MEY6z1Gq" %}
Custom Loading.xd
{% endfile %}


# Custom loading page

Show a special loading page for a specific page.

<figure><img src="/files/Q1mgQ0xuDQoikcbvlaPE" alt=""><figcaption><p>Custom loading in multiple pages</p></figcaption></figure>

Create a custom loading design page for a specific page which will display in place of the default Bravo loading screen.

:round\_pushpin:**Where to add the tags**: Top-level app page

The setup will consist on the following two tags, one for each of the pages involved. Replace *<mark style="color:red;">groupname</mark>* with any name of your choice that identifies the group of those two pages.

* <mark style="color:red;">`[state:default:`</mark>*<mark style="color:red;">`groupname`</mark>*<mark style="color:red;">`]`</mark>: this tag will be added in the top-level element of the page.
* <mark style="color:red;">`[state:loading:`</mark>*<mark style="color:red;">`groupname`</mark>*<mark style="color:red;">`]`</mark>: this tag will be added in the top-level element of the personalised loading page.

## 💾 Example file <a href="#example-files" id="example-files"></a>

Duplicate the file below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/982582280773615281/Bravo-Sample%3A-Custom-loading>" %}

**App use cases using multiple custom loadings:**

{% embed url="<https://www.figma.com/community/file/1217435722039388173>" %}


# No loading

Avoid showing the loader on specific user actions

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag allows to hide the loader when the app needs to load external data, like on navigation or when running remote actions. A common use case is not showing the loader when the user taps [like buttons](/bravo-tags/components/stateful-component-like-button).

**📍 Where to add the tag:** A component layer

```
[no-loading]
```

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;Just add the tag in the layer where the action is triggered, such as a [remote action](/data-binding/data-binding-types/data-binding-add-remote-actions-to-your-ui) or an element with a [navigation link](/set-up-design/setting-up-your-design-file/app-navigation).

<figure><img src="/files/JdL0Y9aJBAK58xTRtucc" alt=""><figcaption></figcaption></figure>


# Preload

Optimising asset loading feature

The <mark style="color:red;">`[preload]`</mark> tag is designed to improve asset loading by including them in the App bundle, reducing the occurrence of loading spinners and provides a smoother user experience. Think of it as an offline mode for assets.

{% hint style="info" %}
This feature is supported only in final apps and cannot be tested on Bravo Vision.
{% endhint %}

Use it specifically for assets that stay permanent in the app and don't change too often, like menu icons and the search icon. Keep in mind that including these assets in the app bundle will increase its size, so it's advisable to use this feature occasionally.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

```
[preload]
```

:round\_pushpin:**Where to add the tag:**

Apply this tag at **any level**: top-level app page, containers, or individual components such as icons, text or images that you want to include in the app bundle to reduce loading spinners experiences.&#x20;

{% hint style="warning" %}
We recommend the preload tag usage **only** **for permanent assets** such as menu icons as using it frequently will consequently increase the app bundle's size.
{% endhint %}

## :hourglass\_flowing\_sand:**How It Works** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. **Placement**: In any page, container, or component, add the following tag: <mark style="color:red;">`[preload]`</mark>.
2. **Build request**: The page, container, or components will be included in the app bundle when you request the build.
3. **Asset Update**: If you make changes to the page, container, or component, we recommend requesting a new build; otherwise, you might end up with two versions of the asset in the app bundle. The previous and the new version will be included. Requesting a new bundle ensures only the latest changes are included.

### :floppy\_disk: **Example design file**

Have a look at the following example to see how you can leverage to include this feature in your Bravo apps.\
\
**Figma file design:**

{% @figma/embed fileId="cX9z61rITQD8Uj6aVkfxye" nodeId="0:1" url="<https://www.figma.com/file/cX9z61rITQD8Uj6aVkfxye/Bravo-Sample%3A-Preload?mode=design&node-id=0-1&t=3vXqxdasosHasIaR-0&type=design>" %}

Your feedback is valuable to us. If you have any suggestions, questions, or issues, please don't hesitate to reach out to the [community](https://community.bravostudio.app/home).


# Form & input fields

Create native forms with different input formats

{% hint style="info" %}
[Upgrade your free account](/get-started/unlock-power-features-to-create-interactive-apps) to the **Bravo Solo plan** to use this feature.
{% endhint %}

Add forms in your apps to receive data from users! Use different input types to create native forms in your apps.

![](/files/A8vn9i2MZ58YEERH1BU1)

## 📲 Input types

Bravo supports the following input types for the forms. See the [example design](#undefined) to see how to set them up in the design file.

**Single-line text**

Create a single-line text input.&#x20;

* The field in your backend should be of type text.

```
[component:input-text]
```

**Multi-line text (text area)**

Create a multi-line text box.

* The field in your backend should be of type text.

```
[component:input-textarea]
```

**Number**

Create a numeric input

* The field in your backend should be of type interger.

```
[component:input-number]
```

**Email**

Create a text input in email format

* The field in your backend should be of type email or text.

```
[component:input-email]
```

**Phone**

Create an input for a phone number

* The field in your backend should be of type text.

```
[component:input-tel]
```

**Date**

Create an input with a date picker.&#x20;

* This is sent as `yyyy-MM-dd` format to the backend.

```
[component:input-date]
```

**Date & Time**

In case you want to send the date as per [ISO 8601](https://es.wikipedia.org/wiki/ISO_8601) (`yyyy-MM-dd'T'HH:mm:ss'Z'`), you can use the following tag (note that the hour will be sent as 00:00:00):

```
[component:input-date:datetime]
```

**Time**

Create an input with a time picker.&#x20;

* This is sent as `HH:mm` format to the backend.

```
[component:input-time]
```

**URL**

Create an input for a URL

* The field in your backend should be of type text or URL.

```
[component:input-url]
```

**Password**

Create an input for a password. The characters in the input will be hidden while the user inputs them.

* The field in your backend should be of type text or password.

```
[component:input-password]
```

**Selector**

Create a dropdown selector with different options. You can specify the options in the design file, or obtain them via API request. See [this page](/bravo-tags/form-and-input-fields/dropdown-selector) to see how to set it up.

* This is sent as text to the backend.

```
[component:input-select]
```

**Image (from phone camera)**

Allows to take a picture with the phone camera and upload it in the form. The phone camera is opened when the user presses the area with the input tag.

* This is sent as image URL to the backend.

```
[component:input-image]
```

**Video (from phone camera)**

Allows to record a video with the phone camera and upload it in the form. The phone camera is opened when the user presses the area with the input tag.

This is sent as video URL to the backend.

{% hint style="warning" %}
The maximum video size is 200MB.
{% endhint %}

```
[component:input-video]
```

**File**

Allows to upload a file that already exists in the phone storage. The option to select a file is opened when the user presses the area with the input tag.

* This is sent as URL to the backend.

```
[component:input-file]
```

\
**Hidden** **Input**

Hidden form field from the user interface but still exists within Bravo. This type of input field can be used to store session identifiers or any other data that needs to be passed along with form submissions but doesn’t need to be visible or editable by the user.

```
[component:input-hidden]
```

### Adding a required input field

You can easily make an input field **required** (mandatory for the user to fill in before sending the form), by appending `:required` at the end of the input tag. For instance, `[component:input-text:required]`.

If a user tries to submit the form without filling in all the required fields in the form (if any), an alert message will be displayed, and the form won't be submitted.

{% hint style="info" %}
The <mark style="color:red;">`[component:input-select]`</mark>and [radio button (single-select)](/bravo-tags/form-and-input-fields/stateful-input/radio-buttons-single-select) component **do not support the** [<mark style="color:red;">`:required`</mark>](/bravo-tags/form-and-input-fields#adding-a-required-input-field) attribute and **requires an option selection by default**.  However, its possible to add an empty option such as "<mark style="color:red;">`=None`</mark>" so users can select an empty value.
{% endhint %}

## 🎨 Creating a form in the design file

To create a form in your app, add as many of the inputs above as you wish. Each input type will require a different setup, check out the [example design file](#example-design-file) to see how to create them.

Once you have added all the inputs, surround them with a [container](broken://pages/-MfgiCryp4HdueTetP8C). All the form inputs must be inside the same container.

Finally, add a button that will trigger the submit action when pressing it, once the user has filled in the form fields. This button **must be inside the form container**. To add it, create the button design, and attach the `action:submit` tag to it.

![](/files/wx85sUcRIbzHrYVSC6Eq)

Also, note that all the form inputs **need to be in the same app screen**, together with the submit button.

## 🔌 Sending form data via API request

Once the design file with the form is imported into Bravo, an API request needs to be bound to the form and its inputs. There are two different types of requests that can be bound to forms:

* A [**POST** request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request), to create a new record in the database.&#x20;
* A **PATCH** request, to update an existing record in the database.

Once the API request has been created, the form input fields need to be bound to the UI elements as explained in the following pages:

{% content-ref url="/pages/-Mflqdp7MgJmD1I9Voub" %}
[Send form input to a database](/bravo-tags/form-and-input-fields/data-biding-send-form-input-to-a-database)
{% endcontent-ref %}

{% content-ref url="/pages/-MlB8eoip-nCcuajRtfp" %}
[API binding types](/data-binding/data-binding-types/bind-multiple-properties-to-a-ui-element)
{% endcontent-ref %}

## 💾 Example design file

See the example below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981976861747536392>" %}


# Password Visibility Toggle

The Password Visibility Toggle is a feature that effortlessly hides/reveals your password on login and signup screens for enhanced security and convenience.

### Requirements

* Figma File design
* Password input field
* Updated Bravo Vision or New build for your published app

***

### :point\_right: The Tag

In order to set up the password visibility toggle, you need this tag in your app page.

| Tag                                                           | Description                                                                                                                                                                                                                                                                                                               |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <mark style="color:red;">`[action:toggle-password]`</mark>    | <p>Use it for the element that will be triggering the action to hide and reveal the password. <br>Could be used in <a href="https://docs.bravostudio.app/bravo-tags/components/stateful-component-like-button#binding-the-map-component-to-marker-data">stateful components</a> or a single component without states.</p> |
| Level: inside a <mark style="color:red;">`[container]`</mark> |                                                                                                                                                                                                                                                                                                                           |

### :label:How to add the tag

<figure><img src="/files/MC1vLlSQTcjTgcahhBa0" alt=""><figcaption><p>Toggle Password</p></figcaption></figure>

***

1. Add the toggle design to your input password. You can design it as a single component or a stateful component with default and active states. Learn more about stateful components [here](https://docs.bravostudio.app/bravo-tags/components/stateful-component-like-button#binding-the-map-component-to-marker-data).
2. Add the following tag <mark style="color:red;">`[action:toggle-password]`</mark> to the component.
3. If you are using stateful components, the <mark style="color:red;">`[state:default]`</mark> **will hide the password** and <mark style="color:red;">`[state:active]`</mark> **will show** the password.
4. Ready! :tada: Get ready to experience a more user-friendly, secure, and efficient way of managing your passwords. Update your mobile app today and make login and signup a breeze!

### :floppy\_disk: Example design file

***

Have a look at the following example to see how you can leverage to include this feature in your Bravo apps.

**Figma file design:**

{% embed url="<https://www.figma.com/community/file/1296788799871361105>" fullWidth="false" %}
Figma File sample app
{% endembed %}

Your feedback is valuable to us. If you have any suggestions or questions, please don't hesitate to reach out to us in the [community](https://community.bravostudio.app/home).


# Stateful input

Create a stateful input component in a form

Create a stateful input component in a [form](/bravo-tags/form-and-input-fields/data-biding-send-form-input-to-a-database), which sends a boolean value via API request (**True** or **False**) depending on whether the user checked it or not.

{% hint style="info" %}
In this example, we'll create a **square checkbox**. However, you can create the design you wish, like a radio button, a toggle or any other shape.
{% endhint %}

To create a stateful input component, you have two options:

1. **Using Figma variants:** Create two versions of the component - one for the active ('checked') state and one for the default ('unchecked') state using Figma variants.
2. **Using Bravo tags**: Create the active and default components separately in the design file, and add Bravo tags to them.&#x20;

## The tags

To create the component, you need to create two components states: **active** and **default**.&#x20;

```
[state:default]
[state:active]
```

These components must be surrounded by a group with the following tag:

```
[input-state-set:{identifier-name}]
```

The result will be the same, regardless of the option you choose.

{% hint style="info" %}
Note that if you're working with **Adobe XD**, you must use **Bravo tags.**
{% endhint %}

## 🎨 Design file setup <a href="#design-file-setup" id="design-file-setup"></a>

### 1. Using Bravo **Tags**

1. Create the two components for the active and default states ('checked' and 'unchecked').&#x20;
2. Apply the tags <mark style="color:red;">`[state:default]`</mark>and <mark style="color:red;">`[state:active]`</mark> to each component, respectively.

![](/files/AC2Rmgj0ZMft5pHQBsdr)

3. Group the two components, and set the tag <mark style="color:red;">`[input-state-set:{identifier-name}]`</mark> to the group. Replace <mark style="color:red;">`{identifier-name}`</mark> with a name of your choice. For instance, <mark style="color:red;">`[input-state-set:checkbox]`</mark>.&#x20;

![](/files/p7iTuGm8dDS2tsl3D5sD)

4. Optionally, you can bind [remote actions](/data-binding/data-binding-types/data-binding-add-remote-actions-to-your-ui) to each of the state elements, as in the [stateful component (toggle)](/bravo-tags/components/stateful-component-like-button).

### 2. Using Figma variants

1. &#x20;Draw the element with Figma and create a [**component**](https://help.figma.com/hc/en-us/articles/360038662654-Guide-to-Components-in-Figma).&#x20;

![](/files/fpcMvNtS5wHhYvPEpwp4)

2. &#x20;Once you have the component, add a [**variant**](https://help.figma.com/hc/en-us/articles/360056440594) to it.&#x20;

![](/files/gzokIJ54SWxEZC0ZyN7f)

3. &#x20;With both variants in place, design each version according to its intended state. Create one version to represent the 'unchecked' state and the other to depict the 'checked' state.

![](/files/ybiEcn7ISfen09ycy0vw)

4. &#x20;**Important:** Each variant must have a property called <mark style="color:red;">`state`</mark>.  For the 'unchecked' component, ensure that the state property is configured to **default.**

{% hint style="info" %}
See [here](https://help.figma.com/hc/en-us/articles/360056440594#Add_properties_and_values) how to add properties to the variants.&#x20;
{% endhint %}

![](/files/gpChMNjF0p8UiTPnMqXP)

5. &#x20;For the 'checked' component, it must be set to **active**.

![](/files/qwjcb9se5Z2f6ynbl2JI)

6. &#x20;Add the variants to your design by navigating to the **Assets tab** in the left menu. Locate the checkbox, now available as a **Local Component**. Drag it into the design twice, ensuring you have both variants. Then, position them to **overlap**, and set the state of one to 'active' and the other to 'default'.

{% embed url="<https://www.loom.com/share/5031199b82b943388e7d7d82f52ae8e7>" %}

7. Once both components are in place, group them together and set the tag <mark style="color:red;">`[input-state-set:`</mark><mark style="color:green;">`{identifier-name}`</mark><mark style="color:red;">`]`</mark>, where <mark style="color:green;">`{identifier-name}`</mark> is a name of your choosing (e.g., `[input-state-set:`<mark style="color:green;">`checkbox`</mark>`]`) .&#x20;
8. Optionally, you can bind [remote actions](/data-binding/data-binding-types/data-binding-add-remote-actions-to-your-ui) to each of the state elements, as in the [stateful component (toggle)](/bravo-tags/components/stateful-component-like-button).

![](/files/p7iTuGm8dDS2tsl3D5sD)

## 🔌 Binding remote actions (optional)​

Optionally, you can bind a [remote action](/data-binding/data-binding-types/data-binding-add-remote-actions-to-your-ui) to the stateful input component. This allows to keep track of the component state in the backend, before the user submits the form.

To set up the remote actions and the backend, check out [this section](https://docs.bravostudio.app/bravo-tags/interactive-component/stateful-component-like-button#binding-the-map-component-to-marker-data) of the Stateful Component documentation.

## 💡 Setting up a initial state (optional)

By default, the state of the stateful input will be default ('unchecked'). In case you want to change this, you can bind a property called **Initial State** in the [**Data Binding**](/data-binding/display-data-in-your-app/data-biding-bind-data-to-ui-for-a-detail-page) section, after importing the design file into Bravo.

![](/files/2Iu1pBObktpU6fb246TV)

The data item you bind to it must return any of these options:\
two text values: <mark style="color:red;">`default`</mark> or <mark style="color:red;">`active`</mark>, boolean value <mark style="color:red;">`true`</mark> or <mark style="color:red;">`false`</mark> or interger <mark style="color:red;">`0`</mark> or <mark style="color:red;">`1`</mark>. \
\
In the first case, if you don't bind this property, the state will be <mark style="color:red;">`default`</mark>, so normally you'll want to have <mark style="color:red;">`active`</mark> as the data item value.

![Row in the backend containing the initial state for the stateful input.](/files/oFcGUAYv2vDq8oUXHJaW)

## 💾 Example files

Example design with **all input fields:**

{% embed url="<https://www.figma.com/community/file/981976861747536392>" %}

Example design showcasing checkboxes (both [**stateful component**](/bravo-tags/components/stateful-component-like-button) and [**stateful input component**](#the-tag)):

{% @figma/embed fileId="9Q5AB7q4jHO2qCIoCF5kHt" nodeId="2:3" url="<https://www.figma.com/file/9Q5AB7q4jHO2qCIoCF5kHt/Bravo-Sample%3A-Checkbox?node-id=2%3A3>" %}


# Checkboxes (Multiple select)

This feature allows you to create **multiple-select** option input component within a form.&#x20;

## :point\_right: The tags

To achieve this, you need to set up each group to the same form value variable in the binding (so it’s send as a unique variable) and there are several tags need to be configured for proper functionality:

1.  <mark style="color:red;">`[input-state-set]`</mark><mark style="color:red;">:</mark> Defines the setup of a component with an input and states.
2. <mark style="color:red;">`[input-group:<multiple>:`</mark><mark style="color:green;">`{identifier-name}`</mark><mark style="color:red;">`]`</mark> Defines the multiple functionality of the radio buttons, all groups need to have the same identifier name.
3. <mark style="color:red;">`[input-value:`</mark><mark style="color:green;">`{value}`</mark><mark style="color:red;">`]`</mark>: This tag sets the value of the element that will be send if active when form submits. It is **optional** as this can be set using binding or static binding.
4.   <mark style="color:red;">`[state:default]`</mark> and <mark style="color:red;">`[state:active]`</mark> sets the different states for the elements.

## :label: How to add the tag

In this example, we've created an input group featuring three options: Cats, Dogs, and Birds. The input group functions as a multiple-select checkboxes.

<figure><img src="/files/K6xo7U1J1o0XZj08mpfE" alt=""><figcaption></figcaption></figure>

1. Create [stateful components](/bravo-tags/components/stateful-component-like-button) by designing both the active <mark style="color:red;">`[state:active]`</mark> and default <mark style="color:red;">`[state:default]`</mark> states for each checkbox. Additionally, you can use the pressed state <mark style="color:red;">`[state:pressed]`</mark>.&#x20;
2. Ensure these components are appropriately grouped for each option. In this example, we have three groups: `Select Cats`,  `Select Dogs`  and  `Select Birds` .
3. Add the tag <mark style="color:red;">`[input-state-set]`</mark> to each group. Also add the tag <mark style="color:red;">`[input-group:multiple:`</mark><mark style="color:green;">`{identifier-name}`</mark><mark style="color:red;">`]`</mark> to add the multiple-select functionality.  All groups must have the same  <mark style="color:green;">`{identifier-name}`</mark> <mark style="color:green;"></mark><mark style="color:green;">.</mark> In our example, the identifier name is green.
4. Optionally, you can incorporate the tag <mark style="color:red;">`[input-value:`</mark><mark style="color:green;">`{value}`</mark><mark style="color:red;">`]`</mark> to the active state to set the value that you want to save to your backend. In our example, the value is `cats` for the `Select Cats` group.
5. Repeat the same steps with the other existing options.
6. Make sure there is a submit button with the <mark style="color:red;">`[action:submit]`</mark> tag to submit the form.

## 🔌 Binding with the API

For this example we'll be using [Xano](https://www.xano.com/) as our backend. In our database, we have a user table with a simple text field called `pets` which we want to connect to our multiple-select option input checkbox component.

You should have completed setting up the API POST or PATCH request in order to bind data. See here how to [Set up an API POST request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request).

<figure><img src="/files/kwjOgJ0hcc59m1sx0o8i" alt=""><figcaption><p>POST API request in Bravo</p></figcaption></figure>

As you'll see in the image above, we're using a unique variable <mark style="color:red;">`${pets}`</mark> for the three pets options : Cats, Dogs and Birds.

<figure><img src="/files/Mmw6hlfr72gwxCRiSV1g" alt=""><figcaption><p>Binding section</p></figcaption></figure>

In this example, we're going to bind the group component "Select Cats". To bind:

1. On the left side of the screen, under "**Elements**," select the group element representing the checkbox.  Alternatively, you can choose the element directly from the image in the middle of the screen.
2. On the right-hand side, under "**Form Data,**" connect the form input to the request variable. To achieve this, choose your data collection, the POST request, and finally, the variable named  `pets`.
3. Repeat **Step 1** and **Step 2** for the remaining available options.

## :floppy\_disk: Example File

{% embed url="<https://www.figma.com/community/file/1329781281924541705>" fullWidth="false" %}

If you're looking for a single-select component, refer to the guide below:

{% content-ref url="/pages/MiiBKA6OYTBqktT8yJPB" %}
[Radio buttons (Single select)](/bravo-tags/form-and-input-fields/stateful-input/radio-buttons-single-select)
{% endcontent-ref %}


# Required Checkbox

A required checkbox is necessary feature in digital forms and agreements, requiring users to explicitly agree to specific terms before proceeding. Key uses include terms and conditions, privacy policy, risk acknowledgment, age verification, etc.

{% hint style="danger" %}
[Firebase Authentication](/integrations/user-authentication/app-login-firebase) currently does not support this feature.
{% endhint %}

In this guide, you'll learn how to make a checkbox or any toggle mandatory.

<figure><img src="/files/fi2BOCWjTq4LEb2SfRjp" alt=""><figcaption></figcaption></figure>

## 👉 The tags

To apply the stateful input:

```
[input-state-set:{identifier-name}] // add the input functionality
[state:default] // sets the default state
[state:active] // sets the active state
```

To make the input mandatory:

```
[forced-selected]
```

To send the input value to the backend use:

```
[input-value:0]
[input-value:1]
```

## 🏷️ How to add the tag

Here's how you can implement it:

1. Create and design your stateful input by following the steps below:

{% content-ref url="/pages/pBEbtVdB8cRb5R0JlS39" %}
[Stateful input](/bravo-tags/form-and-input-fields/stateful-input)
{% endcontent-ref %}

2. Apply the `[force-selected]` tag to the input group to make the input field mandatory.

<figure><img src="/files/JKi9rnBhyCN2mR3s5nDe" alt=""><figcaption></figcaption></figure>

2. Specify `[input-value:0]` for the default state (False), and `[input-value:1]` for the active state (True).

<figure><img src="/files/4Swb53fBqIYPD3mksNxF" alt=""><figcaption></figcaption></figure>

3. Ensure that you add the `[action:submit]` attribute to the submit button. This will trigger the action to submit the data to your backend.

<figure><img src="/files/jdDSMJfjR53gFrOBgIpJ" alt=""><figcaption></figcaption></figure>

## 🔌 Binding with the API

To bind:

1. On the left side of the screen, under "**Elements**," select the group element representing the checkbox. In this case, we're selecting the default state. Alternatively, you can choose the element directly from the image in the middle of the screen.
2. On the right-hand side, under "**Form Data,**" connect the form input to the request variable. To achieve this, choose your data collection, the [POST request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request), and finally, the variable named `verified`.

<figure><img src="/files/uds18MPylIaJAMQ22nZ0" alt=""><figcaption></figcaption></figure>

3. Don't forget to set up the Form Response (On Success and On Error) by clicking on the element where the `[action:submit]` tag is located.&#x20;

<figure><img src="/files/YD6ihkWuN6fmvI4otewn" alt=""><figcaption></figcaption></figure>

## 💾 Example File

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1363154305517504845>" %}

Your feedback is valuable to us. If you have any suggestions or questions, please don't hesitate to reach out to us in the [community](https://community.bravostudio.app/home).


# Radio buttons (Single select)

This feature allows you to create single select option input component within a form.&#x20;

## :point\_right: The tags

To achieve this, you need to set up each group to the same form value variable in the binding (so it’s send as a unique variable) and there are several tags need to be configured for proper functionality:

1.  <mark style="color:red;">`[input-state-set]`</mark><mark style="color:red;">:</mark> Defines the setup of a component with an input and states.
2. <mark style="color:red;">`[input-group:<single>:`</mark><mark style="color:green;">`{identifier-name}`</mark><mark style="color:red;">`]`</mark> Defines the functionality for a single select of the radio button. All groups must have the same name.
3. <mark style="color:red;">`[input-value:`</mark><mark style="color:green;">`{value}`</mark><mark style="color:red;">`]`</mark>: This tag sets the value of the element that will be send if active when form submits. It is **optional** as this can be set using binding or static binding.
4.   <mark style="color:red;">`[state:default]`</mark> and <mark style="color:red;">`[state:active]`</mark> sets the different states for the elements.

## :label: How to add the tag

In this example, we've created an input group featuring three options: Madrid, Barcelona, and Valencia. The input group functions as a single-select radio button.

<figure><img src="/files/L0LCR4TSlxHrMEyRyn89" alt=""><figcaption></figcaption></figure>

1. Create [stateful components](/bravo-tags/components/stateful-component-like-button) by designing both the active <mark style="color:red;">`[state:active]`</mark> and default <mark style="color:red;">`[state:default]`</mark> states for each radio button. Additionally, you can use the pressed state <mark style="color:red;">`[state:pressed]`</mark>.&#x20;
2. Ensure these components are appropriately grouped for each option. In this example, we have three groups: `Select Madrid`,  `Select Barcelona`  and  `Select Valencia` .
3. Add the tag <mark style="color:red;">`[input-state-set]`</mark> to each group. Also add the tag <mark style="color:red;">`[input-group:single:`</mark><mark style="color:green;">`{identifier-name}`</mark><mark style="color:red;">`]`</mark> to add the single-select functionality.  All groups must have the same  <mark style="color:green;">`{identifier-name}`</mark> <mark style="color:green;"></mark><mark style="color:green;">.</mark> In our example, the identifier name is `blue`.
4. Optionally, you can incorporate the tag <mark style="color:red;">`[input-value:`</mark><mark style="color:green;">`{value}`</mark><mark style="color:red;">`]`</mark> to the active state to set the value that you want to save to your backend. In our example, the value is `Madrid` for the Select Madrid group.
5. Repeat the same steps with the other existing options.
6. Make sure there is a submit button with the <mark style="color:red;">`[action:submit]`</mark> tag to submit the form.

## 🔌 Binding with the API

For this example we'll be using [Xano](https://www.xano.com/) as our backend. In our database, we have a user table with a simple text field called `city` which we want to connect to our single-select option input radio button component.

You should have completed setting up the API POST or PATCH request in order to bind data. See here how to [Set up an API POST request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request).

<figure><img src="/files/oIM0zuQ9FRIw4HqqZue0" alt=""><figcaption><p>POST API request in Bravo</p></figcaption></figure>

As you'll see in the image above, we're using a unique variable <mark style="color:red;">`${city}`</mark> for the three city options : Madrid, Barcelona and Valencia.

<figure><img src="/files/DuIF69vvSm5PXpiuXEQR" alt=""><figcaption><p>Binding section</p></figcaption></figure>

In this example, we're going to bind the group component "Select Madrid". To bind:

1. On the left side of the screen, under "**Elements**," select the group element representing the radio button.  Alternatively, you can choose the element directly from the image in the middle of the screen.
2. On the right-hand side, under "**Form Data,**" connect the form input to the request variable. To achieve this, choose your data collection, the POST request, and finally, the variable named `city`.
3. Repeat **Step 1** and **Step 2** for the remaining available options.

## :floppy\_disk: Example File

{% embed url="<https://www.figma.com/community/file/1329781281924541705>" %}

If you're looking to set up checkboxes with multiple-select functionality, refer to:

{% content-ref url="/pages/AyEPOD0BZmMRG1KdPvrB" %}
[Checkboxes (Multiple select)](/bravo-tags/form-and-input-fields/stateful-input/checkboxes-multiple-select)
{% endcontent-ref %}


# Input time Interval

Create the time interval that you want!

<figure><img src="/files/Kh28Ifabozykuqsxqmas" alt=""><figcaption></figcaption></figure>

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

**📍 Where to add the tag:** Inside a container frame in any shape layer (3rd level)

```
[component:input-time:30]
[component:input-time:5]
[component:input-time:1]
...
```

<figure><img src="/files/QQ3FSz0ZAstrXue7MxyL" alt=""><figcaption></figcaption></figure>


# Dropdown selector

Creates a selector input component.

The selector input contains the following properties:

* **Placeholder Value**: the text that will appear as a placeholder, before the user chooses an option. It can be set statically in the design tool, or bound to API data.
* **Options**: This list consists of choices for the selector input. Each choice includes:

  * **Label: T**he text visible to the user in the dropdown selector.
  * **Value**: Represents the data sent to the API.&#x20;

  The label and value can be identical and the options can be statically set in the design file or dynamically linked to API data.
* **Input Destination**: This will be the variable defined in the [POST request body](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request#how-to-set-up-a-post-request), which will take the value of the chosen option.&#x20;

## 👉 **The Tags** <a href="#the-tags" id="the-tags"></a>

The dropdown selector component allows users to choose one option from multiple choices. It can be used either statically or dynamically bound to an API.

**📍 Where to add the tag:** A **text** component inside a [form.](/bravo-tags/form-and-input-fields/data-biding-send-form-input-to-a-database)

```
[component:input-select]
```

**Note:** This input component is part of a form and should include a <mark style="color:red;">`[action:submit]`</mark> tag.

## Static data from Figma <a href="#static-data-from-figma" id="static-data-from-figma"></a>

To define the selector options statically within the tag, use:

```
[component:input-select:value1=label1,value2=label2,value3=label3]
```

Example:&#x20;

<mark style="color:red;">`[component:input-select:pet1=Cat, pet2=Dog, pet3=Bird]`</mark>

If you want the static options **label** and **value** to match:

```
[component:input-select:Label1,Label2,Label3]
```

Example:

<mark style="color:red;">`[component:input-select:Cat, Dog, Bird]`</mark>\
\
In case you want to define static **empty options,** follow:

```
[component:input-select:value1=label1,value2=label2,=None]
```

{% hint style="warning" %}
The <mark style="color:red;">`[component:input-select]`</mark>component **does not support the** [<mark style="color:red;">`:required`</mark>](/bravo-tags/form-and-input-fields#adding-a-required-input-field) attribute and **requires an option selection by default**.  However its possible to add an empty option such as "=None" so users can select an empty value.
{% endhint %}

Example:&#x20;

<mark style="color:red;">`[component:input-select:pet1=Cat, pet2=Dog, pet3=Bird, =None]`</mark>

<figure><img src="/files/yURmQC4gRuw9ms7t890X" alt=""><figcaption><p>How to set up static tag in Figma for a dropdown selector component</p></figcaption></figure>

## Dynamic data from an API <a href="#dynamic-data-from-an-api" id="dynamic-data-from-an-api"></a>

To bind dynamic data to the dropdown selector, ensure you have an API collection ready in Bravo. Use a POST or PATCH request since this component is part of a form.

1. In the Figma design, make sure to create this tag within a [form](/bravo-tags/form-and-input-fields).
2. Add the tag <mark style="color:red;">`[component:input-select]`</mark> in a **text** component in the design file.&#x20;

![](/files/ny7KaYMlwXDJP50uD6DE)

{% hint style="warning" %}
Don't surround the labels/values with commas and don't add any spaces inside the tag.
{% endhint %}

3. [Import the design file](/good-to-know/faq/importing-a-design-file) into Bravo if not done yet. If already imported, sync the file and go to the app's binding section.
4. Ensure you have created a valid [POST request](/bravo-tags/intro-and-onboarding/post-login-page-onboarding) beforehand. &#x20;
5. Bind the `input-select` element to the **Form data** property to the variable defined in the [POST request body](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request#how-to-set-up-a-post-request) that you want to bind to the form. This body might have more variables, that you might want to bind to other input fields, in case the form has more.
6. Bind the **Options** property to a **list data record**. Set the **Label** and **Value** properties to the corresponding data from the API. Remember that the **Label** is the property the user will see in the app, while the **Value** is the actual data sent via API request. In this example below, those two properties are connected to the same data item, but they don't always have to.

![](/files/9U8wt4HwAUMeCA2vFjz1)

7. Optionally, you can bind the **Form Initial Value** to a **GET request.** This is useful if you enable data editing.
8. Finally, bind the **Form response actions (On success or On Error).**
9. Now, the selector input component should be ready! Test and preview it on **Bravo Vision**. 🚀

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/981976861747536392>" %}


# Slider control

The input slider control component is represented visually as a horizontal track with a moveable element, known as the thumb, which users can drag along the track.&#x20;

Now, with this component, users can slide this to adjust values like the temperature settings in smart home devices or price ranges in online shopping filters.

<figure><img src="/files/jSmBEKUVBpbewPaA0SpK" alt=""><figcaption></figcaption></figure>

### :point\_right: The Tag

To insert a slider control into your interface, use the following tag format:

```
[component:input-slider:<min>:<max>:<step>:<value>
```

**📍 Where to add the tag:** A rectangle layer.

Replace `<min>`, `<max>`, `<step>`, and `<value>` with your desired numerical values:

* `<min>` is the minimum value the slider can represent.
* `<max>` is the maximum value the slider can represent.
* `<step>` is the incremental value between the range.
* `<value>` is the current value of the slider.

Example usage:

```
[component:input-slider:0:100:5:25]
```

This creates a slider that ranges from 0 to 100, moves in increments of 5, and has an initial value of 25.

### :art: **Customize its style**

To enhance the visual appeal of your slider control, apply custom styling. Here are the tags you can use to define the style:

* **Background Color:** `[style:bg-color:#HEXCODE]` - This sets the background color of the slider track. Replace `#HEXCODE` with the 6-digits hex color code of your choice.
* **Active Color:** `[style:active-color:#HEXCODE]` - This changes the color of the active portion of the slider (from the minimum value to the current thumb position). Replace `#HEXCODE` with your preferred 6-digits hex color code.
* **Thumb Color:** `[style:color:#HEXCODE]` - This determines the color of the thumb, which is the draggable circle on the slider. Use a 6-digits hex color code to specify the color.

For example:

```
[style:bg-color:#42476ee]    // Sets the background color of the slider track to dark blue.
[style:active-color:#d9d9d9]    // Changes the active portion of the slider to a light grey.
[style:color:#50e3c2]    // Sets the thumb color to a mint green.
```

Incorporate these style tags in your code to customize the look of your input slider to match your interface design.

### :label:How to add the tag

In order to successfully integrate an input slider control into your user interface, follow these steps:

1. Draw a rectangle on your design canvas to represent the slider control. We recommend a **minimum height of 32px** at least.

<figure><img src="/files/odPqK2kGJvoIltrJgSkD" alt=""><figcaption></figcaption></figure>

2. Incorporate the following tag into the rectangle to embed the slider functionality:

```
[component:input-slider:0:100:5:25]
```

3. To customize the slider's appearance, add these style tags directly after the slider component tag:

```
[style:bg-color:#42476e][style:active-color:#d9d9d9][style:color:#50e3c2]
```

4. Make sure your user interface design includes a submit button. Place the tag `[action:submit]` in the button to link the action correctly.

### :link:  Binding with your API

1. Ensure your [POST or PATCH API request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request) is properly set up.
2. From the left side of the screen, under the Elements section, select the slider control, or directly tap on the slider image displayed in the center of the screen.
3. Navigate to the Form Data section on the right, choose your API collection, and then select either the POST or PATCH request. Finally, specify the variable you wish to use.

<figure><img src="/files/uoKhm90hfIjv8J1rlO4u" alt=""><figcaption></figcaption></figure>

4. Proceed by selecting the submit button and configuring the form response action to finalize the integration.

<figure><img src="/files/lUj1mejC1XhraBuViB7u" alt=""><figcaption></figcaption></figure>

5\.  And you're set! You should be ready to [test it with Bravo Vision](/good-to-know/faq/bravo-vision)! :tada:

### :floppy\_disk: Example design file

{% @figma/embed fileId="Bc0Wk18HQpN3DDlu0rZpHx" nodeId="569:2" url="<https://www.figma.com/file/Bc0Wk18HQpN3DDlu0rZpHx/Slider-bar?mode=design&node-id=569-2&t=LgwIrmJ0VYc0YosM-0&type=design>" %}

Your feedback is valuable to us. If you have any suggestions or questions, please don't hesitate to reach out to us in the [community](https://community.bravostudio.app/home).


# Calendar picker

The calendar picker is a user interface component that lets users select a specific date, which is then submitted to your backend in [ISO format](https://en.wikipedia.org/wiki/ISO_8601).

<figure><img src="/files/iCfZmaKKgw1WC2U0Qa4u" alt=""><figcaption></figcaption></figure>

## 👉 **The Tags**

**📍 Where to add the tag?** A rectangle laye&#x72;**.**

To incorporate a calendar into your app, choose the appropriate tag based on your needs:

**Select one day**

For allowing users to select a single date, use the `single` tag:

```
[component:input-calendar:single]
```

**Select multiple non-consecutive dates**

To enable selection of **multiple non-consecutive dates**, utilise the `multiple` tag:

```
[component:input-calendar:multiple]
```

**Range**

To select a range of dates including start and end dates, use the following syntax:

```
[component:input-calendar:range]
```

<figure><img src="/files/qb0DbgCScPn2tDj1Ehv8" alt=""><figcaption></figcaption></figure>

## ️:paintbrush: Calendar styling

**Add a specific text color**

```
[style:color:<color>]
```

**Add a color to the active text**

```
[style:active-text-color:<color>]
```

**Add a color to the selected date**

```
[style:active-color:<color>]
```

**Add a background color**

```
[style:bg-color:<color>]
```

<figure><img src="/files/TN3YNfzhB2P0EOwGKfCK" alt=""><figcaption></figcaption></figure>

## 🏷️ **How to add the tag**

1. Choose the type of calendar you'd like to use.
2. Paste the tag into the layer name of a rectangle shape.
3. Add a styling tag of your preference.
4. Ensure you include the `[action:submit]` tag, which triggers the action to transmit the data to your backend.
5. [Preview your app on **Bravo Vision**](/get-started/bravo-vision-previewer#how-to-use-bravo-vision)**.** 🚀

## 💾 Example files

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1372181468157618589>" %}

Your feedback is valuable to us. If you have any suggestions or questions, please don't hesitate to reach out to us in the [community](https://community.bravostudio.app/home).


# Send form input to a database

{% hint style="info" %}
[Upgrade your free account](/get-started/unlock-power-features-to-create-interactive-apps) to **Solo** **plan** to use this feature.
{% endhint %}

This tutorial is a continuation after you have set up a POST request to create data to a database.&#x20;

If you haven't done that yet, check out:

👉 [Connect to any API: POST request](/connect-api/set-up-api-requests/creating-an-api-collection/airtable/data-library-connect-to-any-api-post-request)\
\
💡 We're using this [design file](https://www.figma.com/community/file/1388482466816173335) and [this Airtable](https://airtable.com/shrjetk4AeKeUuumw) for the tutorial.

## How to bind POST request to form input design

Connecting functionality to your app design is done in the **Binding Setup** of an app project. `Binding` is the action of connecting an API request to an app element (i.e. text, rectangle, etc.)

1\. In your form design, **add the Bravo Tags for** [**input fields and submit button**](https://www.notion.so/0c35674e8c504dccbc19bc59a6ce0c4b). The example design file already includes these tags.

**Single-line text field:** `[component:input-text]`\
**Number field:** `[component:input-number]`\
**Submit button:** `[action:submit]`

![](/files/7vKsqwFqsecYkRS1WNOa)

2\. Import the design file into Bravo to create a project. 🚀

3\. In your app project page, click on the app screen with the form to enter **Data Binding** mode.

4\. **Select the collection and POST request** you previously created in the Data Library.\
(In this example, we're selecting the collection "**POST demo**" and the request "**Add Scores**".)

5\. In the Visual Elements list, **select your input field layer**.

![](/files/rIZQHVQ4Vl9TtfV54oq5)

<figure><img src="/files/G3E0CnxYoSrlGhhHsxd2" alt=""><figcaption></figcaption></figure>

6\. In the Element Binding side panel, you will see 2 selectable options for the input field: **Value** and **Input Destination**. In case you want to learn more on how to bind these two fields, check out [this page](/data-binding/data-binding-types/bind-multiple-properties-to-a-ui-element#binding-input-field-properties-to-api-data).

{% hint style="info" %}
**Value**: The data that is replacing the placeholder content.\
**Input Destination**: Where the input data is sent to.
{% endhint %}

7\. Since the POST request is for creating (sending) data to the database, you only need to **select the input for Content Destination**.

{% hint style="info" %}
Notice the Content Destination choices come from the **inputs in the Body of your POST request setup**.
{% endhint %}

![](/files/3PtdDuOYVkK8uhcLR1Yn)

8\. **Repeat step #5-7** until all of your input fields are bound.\
(No binding is needed for the submit button, just make sure you have the submit Tag on that element)

9\. Scroll down to **Response Actions** to configure the action that happens when the user presses the Submit button. By default, the app will show an alert message.

![](/files/Y05KY2fzTfaZvpvga0kN)

**Show Alert**: Display a pop-up message.\
**Go To Page**: Redirects user to another page in the app.\
**Open URL**: Opens the web browser on the phone with the specified URL.

10\. Test out your native form page with **Bravo Vision**! 📱

![](/files/s8Aw3vbeGXxZdIsp324U)

That's it! 🎉


# Components


# Autoplay Video

Autoplays an audio-less video when the user is on that app page.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

Autoplays an audio-less video when the user is on that app page. The video will replace the content of a rectangle shape. Supports URL ending in **.mp4**. [More options to add videos](/bravo-tags/mobile-actions/how-to-use-video-components-in-your-apps)**.**

**📍 Where to add the tag:** A rectangle layer

```
//The tag:

[component:video:URL]

//Sample tag to try:

[component:video:https://storage.googleapis.com/coverr-main/mp4%2Fcoverr-sandboarding-in-desert-1585557594519.mp4]
```

![](/files/-MhmPBJSVv5P5xlsfBmI)

{% hint style="info" %}
**What if I have a video file?** You will need to upload the video to an online storage that generates an .mp4 URL. Some suggestions: [AWS S3](https://aws.amazon.com/s3/) or [Airtable](https://docs.bravostudio.app/learn-and-create/bravo-best-practices#database-setup) .
{% endhint %}

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

1. **Copy** the tag.

&#x20;   2\. **Paste** the tag into the layer name of a **rectangle shape**.

![](/files/-Mhm_wpo5JVc5j9Y_QT8)

&#x20;    3\. Replace the placeholder URL with your own (or try our sample tag).

&#x20;   4\. Import to **Bravo Studio** & preview on **Bravo Vision** 🚀 (If you imported the app before, you just need to press the button Update in ***Bravo Studio*** to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/973892292868502990>" %}


# GIF

A GIF will replace the content of the rectangle.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag allows to insert a GIF, which will replace the content of the rectangle layer where the tag is placed. Supports URL ending in **.gif.**

**📍 Where to add the tag:** A rectangle layer

```
//The tag:

[component:gif:URL]

//Sample tag to try:

[component:gif:https://media.giphy.com/media/26ybwt1cT5DfBzRU4/giphy.gif]
```

{% hint style="info" %}
You can also [directly upload a GIF file](https://help.figma.com/hc/en-us/articles/360040028034) into your Figma file to use in your app.
{% endhint %}

![](/files/-MhnO00wEpEDzhxuAfgm)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   1\. **Copy** the tag.

&#x20;   2\. **Paste** the tag into the layer name of a **rectangle shape**.

![](/files/-MhrySxu3gkg62e78Z1P)

&#x20;   3\. Replace the placeholder URL with your own (or try our sample tag).

&#x20;   4\. Import to **Bravo Studio** & preview on **Bravo Vision** 🚀 (If you imported the app before, you just need to press the button Update in ***Bravo Studio*** to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% @figma/embed fileId="dedkxpF23DnniDkjZnqehd" nodeId="104:1" url="<https://www.figma.com/file/dedkxpF23DnniDkjZnqehd?node-id=104:1>" %}


# SVG Component

If your project contains many vector components, it might occupy significant space and could lead to usage limitations on the page, as well as visual issues. If a vector shape layer looks distorted in Bravo Vision or if a layer has two or more effects applied, add this tag to any element, group, or frame to enable Bravo to render it as it appears in Figma.

{% hint style="info" %}
**What is an SVG?**\
\
**SVG (Scalable Vector Graphics)** is an XML-based vector image format used for two-dimensional graphics. It allows for the creation of high-quality graphics that can scale to any size without losing quality. SVG files are widely supported across web browsers and can be used for various purposes, including illustrations, icons, and animations.
{% endhint %}

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

**📍 Where to add the tag:** Inside a container frame in any shape layer (3rd level)

```
[component:svg]
```

![](/files/6GjUMkRXgsAlfKmodXu8)

{% hint style="info" %}
The <mark style="color:red;">`[component:svg]`</mark> tag functions by treating all elements under it as a single and unique element, hence **it cannot be bounded**. \
\
This approach aligns Bravo more closely with Figma. Additionally, it results in performance optimization, particularly on mobile platforms, as only a single element requires rendering rather than multiple entities.
{% endhint %}

{% hint style="info" %}
The <mark style="color:red;">`[component:svg]`</mark>SVGs/vectors  are "fit" to container by default, as they are normally used for icons. Add the <mark style="color:red;">`[shape:fill]`</mark>tag and the SVG will be "fill" to container, which is useful for backgrounds.&#x20;
{% endhint %}


# Web view

A web page will replace the content of the rectangle.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag creates a webview that will replace the content of the rectangle layer where the tag is placed. You can use any public URL.

**📍 Where to add the tag:** A rectangle layer

```
//The tag:

[component:web-view:URL]

//In case you want to bind the URL to API data:

[component:web-view]

//Sample tag to try:

[component:web-view:https://goo.gl/maps/Ub6fY9x8a9DCpdSx8]
```

![](/files/-MhnMGVAUHGtUM9Ok-7h)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   **1. Copy** the tag.

&#x20;   2\. **Paste** the tag into the layer name of a **rectangle shape**.

![](/files/-MhnMT0Jx7yJBX-UeDDi)

&#x20;   3\. Replace the placeholder URL with your own (or try our sample tag).&#x20;

&#x20;   4\. Apart from indicating the URL in the Figma tag, you can bind a URL to API data, in the Data Binding section.

![](/files/LlCk85dxYOgcMy81QcPH)

&#x20;   5\. Import to Bravo & preview on Bravo Vision 🚀 (If you imported the app before, you just need to press the button Update in ***Bravo Studio*** to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/file/dedkxpF23DnniDkjZnqehd/Bravo-Sample%3A-Bravo-Tags>" %}


# Web Components using AI

Here we have the docs necessary to build a custom web component using AI (ChatGPT) and add the HTML code into your Bravo Studio web component library. Additionally, you will be able to preview your web component in your app using our web-view Bravo Tag where your newly created web component will live.

### **Needed**

Bravo Studio [**Solo**](https://www.bravostudio.app/pricing) plan

\[component:web-view: URL] (You can see more about web views [here](https://docs.bravostudio.app/bravo-tags/components/component-webview)).

Paid or Free Chat GPT account. (You can use any AI platform as far as it can create HTML code).

[Bravo Vision](https://www.bravostudio.app/download-bravo-vision) installed to test your app and web component.

### 🥷 How to test

***

1. Create an app page in Figma with a web view tag \[component:web-view: URL] tag or you can duplicate our sample [Figma file here](https://www.figma.com/design/o6sj4INpfxE3TC7GiDTUhR/Web-component-Test?node-id=3-4\&t=Jlptf8CSbWwxGjPm-1).

<figure><img src="/files/n7FXk9t7RSoj7yPir5C6" alt=""><figcaption></figcaption></figure>

2. Now that we have your Figma file ready, we can proceed to import to Bravo Studio.

<figure><img src="/files/Uyy5NuBsLqmn4GCpR0kn" alt=""><figcaption></figcaption></figure>

3. Once imported, we can see our Bravo project and our web view page where we will be adding our web component.

<figure><img src="/files/dIrYZ73KrQQSJHJFU1S2" alt=""><figcaption></figcaption></figure>

4. Now that our app age is ready, we can ask AI to generate our web component code. In our example, we will generate a boxing timer.

\
**This will be our initial prompt:**

Im building a mobile app with Bravo Studio and i would like you to help me build a web component for a specific web view page inside my app. Its a boxing training app and i would like to add a boxing round timer. Please build it and include the following:

* 12 rounds of 3 minutes
* Countdown timer
* 1 minute rest time between rounds
* Round end warning when 10 seconds left to end each round.
* Play a boxing bell sound to start the round, when 10 seconds left to end the round and when the round finishes.
* Please style the timer with red colors and use old style squares typography like if it was an old alarm clock. Use neon style for the red color.
* There should be a start button, a pause button and a reset button.

<figure><img src="/files/earxvSP450DrmPYzgB3x" alt=""><figcaption></figcaption></figure>

5. Chat GPT generates the code for us:

<figure><img src="/files/AxIxKUGAPnsWFga6MDhZ" alt=""><figcaption></figcaption></figure>

6. Heres the actual code if you wish to test the same:

```jsx
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Boxing Round Timer</title>
  <style>
    body {
      font-family: 'Courier New', Courier, monospace;
      background-color: #000;
      color: #fff;
      text-align: center;
      margin: 0;
      padding: 0;
    }
    .timer {
      font-size: 4rem;
      color: red;
      text-shadow: 0 0 10px red, 0 0 20px red;
    }
    .controls button {
      font-size: 1.5rem;
      margin: 10px;
      padding: 10px 20px;
      background-color: red;
      color: #fff;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      text-shadow: 0 0 10px red;
    }
    .controls button:hover {
      background-color: darkred;
    }
    .round {
      font-size: 2rem;
      margin-top: 10px;
    }
  </style>
</head>
<body>
  <h1>Boxing Timer</h1>
  <div class="round">Round: <span id="round-number">1</span>/12</div>
  <div class="timer" id="timer">03:00</div>
  <div class="controls">
    <button id="start-btn">Start</button>
    <button id="pause-btn">Pause</button>
    <button id="reset-btn">Reset</button>
  </div>

  <audio id="bell-sound" src="boxing-bell.mp3"></audio>

  <script>
    const timerDisplay = document.getElementById('timer');
    const roundDisplay = document.getElementById('round-number');
    const bellSound = document.getElementById('bell-sound');
    const startBtn = document.getElementById('start-btn');
    const pauseBtn = document.getElementById('pause-btn');
    const resetBtn = document.getElementById('reset-btn');

    let totalRounds = 12;
    let currentRound = 1;
    let roundTime = 3 * 60; // 3 minutes
    let restTime = 60; // 1 minute
    let timeLeft = roundTime;
    let isResting = false;
    let interval;

    function playBell() {
      bellSound.currentTime = 0;
      bellSound.play();
    }

    function updateTimerDisplay() {
      const minutes = String(Math.floor(timeLeft / 60)).padStart(2, '0');
      const seconds = String(timeLeft % 60).padStart(2, '0');
      timerDisplay.textContent = `${minutes}:${seconds}`;
    }

    function startTimer() {
      if (interval) return;

      interval = setInterval(() => {
        if (timeLeft === 10) playBell();
        
        if (timeLeft > 0) {
          timeLeft--;
        } else {
          playBell();

          if (isResting) {
            isResting = false;
            currentRound++;

            if (currentRound > totalRounds) {
              clearInterval(interval);
              interval = null;
              alert('Training complete!');
              return;
            }

            timeLeft = roundTime;
            roundDisplay.textContent = currentRound;
          } else {
            isResting = true;
            timeLeft = restTime;
          }
        }

        updateTimerDisplay();
      }, 1000);
    }

    function pauseTimer() {
      clearInterval(interval);
      interval = null;
    }

    function resetTimer() {
      pauseTimer();
      currentRound = 1;
      isResting = false;
      timeLeft = roundTime;
      roundDisplay.textContent = currentRound;
      updateTimerDisplay();
    }

    startBtn.addEventListener('click', startTimer);
    pauseBtn.addEventListener('click', pauseTimer);
    resetBtn.addEventListener('click', resetTimer);

    updateTimerDisplay();
  </script>
</body>
</html>

```

7. Now that we can copied the code to our clipboard, we can go back to Bravo Studio. In our project page, let's move to the new project tab called “Components”.

<figure><img src="/files/lHUf58zKVQEnsCeql2au" alt=""><figcaption></figcaption></figure>

8. Once in the components tab, hit the blue + button to create a new component in your components library.

<figure><img src="/files/ajQgWwcj1Q4WPSiI5Ues" alt=""><figcaption></figcaption></figure>

9. After creating your web component, you will find a small code sample and a preview of how that looks as a webview on the right side. (You can even test changing the word hello in the code to see how it changes in our web component previewer. Make sure you press “Save” in order to see the changes).&#x20;

<figure><img src="/files/vQA75aiQDZKAbXHcSiNR" alt=""><figcaption></figcaption></figure>

10. Now that we have all set, lets copy the code that Chat GPT generated for our web component and paste it to our code editor. Make sure to first remove the sample data in it first by selecting all the text with Control + A and Delete.\
    \
    Once its all deleted, paste your web component code and press Save.<br>
11. Now that we have added our code and press Save, you will see your code inside the code editor and the preview of our web component:

<figure><img src="/files/OrKFcvjfaYu4o30RegKg" alt=""><figcaption></figcaption></figure>

10. Remember, every code generated by Chat GPT will be different therefore you may want to adjust your initial prompt with follow up prompts till you get exactly what you are looking for. \
    \
    💡**TIP**: If you want your web component to follow a specific design style, you can also include a screenshot of your app designed in Figma and instruct Chat GPT to respect your overall app design.<br>
11. Feel free to test your newly generated web component inside the web component previewer:

<figure><img src="/files/XHkl1dCaJjnJuk5l5ZIp" alt=""><figcaption></figcaption></figure>

12. Before we can test our web component on our phone using Bravo Vision, we must copy the URL link of our web component by pressing the Copy Link button under our code editor.

<figure><img src="/files/AxKs83vKt8BQ1kAVaXad" alt=""><figcaption></figcaption></figure>

13. Once we have copied our web component unique URL, we must add it to our web-view Bravo Tag in Figma. For this example it looks like this:

\[component:web-view: <https://dev-bravo-apps-assets.s3.eu-central-1.amazonaws.com/U6QB112ECDKCBX5V6N2GGCWRGFYSG9A9F/01JGYQ60TF71JAGBXG53VDQBDX.html>]

**NOTE**: You will need to copy your **own** link from the "Copy link" button.

🚨 Make sure to sync your Bravo project with Figma to make sure our Bravo project updates with the updated Bravo web-view Tag.

<figure><img src="/files/fAbbjEzPMvqUB1JnM7BU" alt=""><figcaption></figcaption></figure>

14. In Figma, we select our web-view Tag container name and replace it with the one above which includes the web component unique URL.

<figure><img src="/files/exSKPB3wqsLzD1uelMaA" alt=""><figcaption></figcaption></figure>

15. Now we can test our app and web component on our mobile device using Bravo Vision:

<figure><img src="/files/xZtQlpkO3RpmaCbwyomg" alt="" width="375"><figcaption></figcaption></figure>

**💡 Learn how to build Advanced web components connecting them to your backend in** [**this blog**](https://www.bravostudio.app/post/advanced-web-components-using-cursor-ai-and-xano-backend)**.**

**Or watch the tutorial:**&#x20;

{% embed url="<https://youtu.be/fysG-1SKcKo?si=e2yurbhiieM8Va2X>" %}

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/design/o6sj4INpfxE3TC7GiDTUhR/Web-component-Test?node-id=3-4&t=Jlptf8CSbWwxGjPm-1>" fullWidth="true" %}


# Web view communication

{% hint style="info" %}
To set up WebView communications, you need **programming skills**, especially in JavaScript, to handle interactions between the app and web content.
{% endhint %}

**What is WebView communication?**\
\
WebView Communications **allow a** [**web view**](/bravo-tags/components/component-webview) embedded in a mobile **to interact with the app** by **exchanging variables** and **triggering actions**, enhancing the app's functionality and user experience. \
\
This involves using HTML, CSS, and JavaScript to create dynamic content that communicates with the app through an API.

#### How Does WebView Work in Bravo?&#x20;

The crucial feature of WebView is its **ability to communicate with the app that contains it**. This is done by **passing variables and sending actions** between the WebView and the app.

* **Passing Variables:** Variables can be sent to the WebView from the app. The variable should be called in the HTML. \
  \
  For instance, if you need to show an interactive map with specific data, you can pass that data from the app to the WebView to dynamically customize the content.<br>
* **Triggering Actions from WebView:** The WebView can also trigger actions in the app. Here are the actions that can be used: "`goto"`, "`goback`", "`openurl`", "`refresh`", "`logout`".\
  \
  For example, in an autocomplete search function: once the user selects an item, the WebView can        send an action to Bravo to navigate to a detail page, seamlessly transitioning from a web view to a native view.

#### Technical Implementation

**HTML and JavaScript**

The content of the WebView is essentially HTML, CSS, and JavaScript. This content is developed outside of Bravo but can interact with Bravo through an API provided by the app.

**Messaging Between WebView and the App**

For the WebView and the app to communicate, a technique similar to [iframes](https://saurabhchirde.hashnode.dev/mastering-the-art-of-communicating-between-window-postmessage-and-iframe-in-javascript-a-beginners-guide) in web development is used. Communication is done through messages sent and received between the app and the WebView.

## :black\_joker: **Use Case: Swipe Functionality with WebView Communication**

This is a generic WebView component with swipe functionality, similar to what you might find in a dating app. As the user swipes left or right, it triggers a go-to action within Bravo to display a pop-up of the swiped item.

To achieve this, you can use WebView Communication within Bravo. Here's how:

1. **Create an HTML** which contains the following:
   1. **Data Loading**: It fetches data from a specified URL to populate the cards with information.
   2. **Interaction Setup:** A swipe-based interaction system for cards, allowing users to swipe left or right to navigate through content.
   3. **Bravo Integration**: Upon completing a swipe, the code sends a message to Bravo via WebView Communication, **indicating the direction of the swipe** and **triggering corresponding actions** within the Bravo app. For instance, when a user swipes left or right, trigger a go-to action within Bravo to display a pop-up of the swiped item.

Below is a demonstration of the code interacting with the WebView:

```
if (successful) {
    // throw card in the chosen direction
    this.topCard.style.transform =
        'translateX(' + posX + 'px) translateY(' + posY + 'px) rotate(' + deg + 'deg)'

    // send message to bravo
    if (direction_page) {
        const params_str = btoa(`{"name":"${this.topCard.textContent}"}`)
        const href_remote_str = `https://apps-service.bravostudio.app/devices/apps/${appid}/node/${direction_page}?params=${params_str}`
        const message = { "action": "goto", "params": {"href": `${direction_page}`,"hrefRemote": href_remote_str} };
        console.log(message)
        if (window.bravo != undefined) { window.bravo.postMessage(message); }
    }
    // wait transition end
    setTimeout(() => {
        // remove swiped card
        this.board.removeChild(this.topCard)

        // add new card
        this.push()
        // handle gestures on new top card
        this.handle()
    }, 200)
}
```

* If the swipe gesture is successful (`if (successful)`), a message is constructed containing information about the swipe direction and the content of the swiped card.
* The constructed message is then sent to Bravo using `window.bravo.postMessage(message)`.&#x20;

**Message Construction**: `message` is constructed as a JavaScript object containing two main properties:

* `"action"`: Specifies the type of action to be performed by the Bravo app. In this case, it is set to **"goto"**, indicating a navigation action.
* `"params"`: Contains parameters related to the action, including:
  * `"href"`: Specifies the destination page within the Bravo app. It is set to `direction_page`, which determines the specific page or screen to navigate to.
  * `"hrefRemote"`: Specifies the remote URL constructed earlier (`href_remote_str`), which provides additional information or parameters for the Bravo app to process during navigation.

In this example, this is where the interaction with WebView Communication occurs, as it sends data from the web content (the swiped card) to the Bravo app for further processing or action triggering.

<figure><img src="/files/WD3PTC9ajSDyH56U7omH" alt=""><figcaption></figcaption></figure>

Using WebView in Bravo opens up many possibilities for creating more dynamic and functional hybrid apps. It allows combining the best of web and native worlds, offering an enriched user experience and advanced functionalities that wouldn't be possible otherwise.

For more in-depth information and to understand the basics of window communication in JavaScript, you can check out this [detailed article](https://saurabhchirde.hashnode.dev/mastering-the-art-of-communicating-between-window-postmessage-and-iframe-in-javascript-a-beginners-guide).

## Example file

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/design/PvtuRD3AUvWgoTNYCxYXtP/WebView-communication%3A-Swipe?node-id=0:1&t=psuspJKnl9gWOKyu-1>" %}

Your feedback is valuable to us. If you have any suggestions, questions, or issues, please don't hesitate to reach out to the [community](https://community.bravostudio.app/home).


# LottieFile

A Lottie will replace the content of the rectangle.

Using this tag, you can insert a Lottie animation that will replace the content of the rectangle shape where you add the tag. Supports URLs ending in **.json**.

**📍 Where to add the tag:** A rectangle layer

```
[component:lottie:<lottie_url>]
```

Example:

```
[component:lottie:https://assets8.lottiefiles.com/packages/lf20_9JaVsy.json]
```

![](/files/-Mhmb6mq0oNQ8zgrFCJf)

### Additional parameters <a href="#adittional-parameters" id="adittional-parameters"></a>

Optionally, you can set how the animation is run with the following parameters:

```
//The tag with optional parameters

[component:lottie:<lottie_url>:<repeat>:<startFrame>:<endFrame>]

//Examples:

//Loop until frame 80
[component:lottie:https://assets3.lottiefiles.com/packages/lf20_h2s9rDrzUP.json:loop:0:80]

//Run only once
loop[component:lottie:https://assets2.lottiefiles.com/packages/lf20_ryWdG6ISch.json:once]
```

| Tag           | Description                                                          | Possible values                                                                                                       |
| ------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| \<repeat>     | How the Lottie animation is run.                                     | <p>"loop" -> Runs the Lottie animation in loop (default).<br><br>"once" -> To run the Lottie animation only once.</p> |
| \<startFrame> | Frame to start the Lottie animation from (default is 0)              | *(any number)*                                                                                                        |
| \<endFrame>   | Frame when the Lottie animation will stop (default is the end frame) | *(any number)*                                                                                                        |

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

### **Option 1 (Figma only)**

&#x20;   **1. Open** the [LottieFiles plugin](https://www.figma.com/community/plugin/809860933081065308) in Figma and **Search** for a Lottie.

&#x20;   2\. Click `Convert to GIF` > `Add to Figma`&#x20;

![](/files/-MhmhKPwB8uOxp3YrLF5)

&#x20;   3\. **Replace the placeholder URL** with your own (or try our sample tag).

![](/files/-MhmhQLKno2q2BL4kjtw)

### **Option 2**

&#x20;   **1. Copy** the tag.

&#x20;   2\. **Paste** the tag into the layer name of a **rectangle shape**.

![](/files/-MhnHGMgqcv939q-3baX)

&#x20;   **3. Replace the placeholder URL** with your own (or try our sample tag).

![](/files/-MhnHKf5PT-2pf0h9Q0J)

&#x20;   4\. **Import** to Bravo & preview on Bravo Vision 🚀 (If you imported the app before, you just need to press the button Update in ***Bravo Studio*** to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/design/dedkxpF23DnniDkjZnqehd/Bravo-Sample%3A-Bravo-Tags?node-id=37-1&t=e5oqQzUJj5caCzjE-0>" %}
Bravo Sample
{% endembed %}


# Lottie-animated component

Create stateful components with Lottie animations

This feature will give dynamism to your components and will enhance the quality of your app! Now you can easily set states by using [dotLottie](https://dotlottie.io/) and [Lottie animations](https://lottiefiles.com/) instead of regular states.&#x20;

## :point\_right: The tags

:round\_pushpin:**Where to add the tags:** A rectangle layer

These are the tags you can use in the design file to implement the toggle component.&#x20;

<mark style="color:red;">`[component:stateful-lottie:<url>]`</mark>

<mark style="color:red;">`[component:input-stateful-lottie:<url>]`</mark>

{% hint style="info" %}
These tags support only URLs ending in **.json**
{% endhint %}

**Available use cases:**

{% tabs %}
{% tab title="Menu icons in tab menu" %} <mark style="color:red;">`[component:stateful-lottie:`</mark><mark style="color:blue;">`<url>`</mark><mark style="color:red;">`]`</mark>

<figure><img src="/files/9v8lwXfUVwlYw8l1y5K5" alt=""><figcaption></figcaption></figure>

Example: \
`[component:stateful-lottie:`*<mark style="color:blue;">`https://assets8.lottiefiles.com/packages/lf20_ei7frqcx.json`</mark>*`]`
{% endtab %}

{% tab title="Checkbox in forms" %} <mark style="color:red;">`[component:input-stateful-lottie:`</mark><mark style="color:blue;">`<url>`</mark><mark style="color:red;">`]`</mark>

<figure><img src="/files/cDVgsdS7cZOBA6UYz3PA" alt=""><figcaption></figcaption></figure>

Example:&#x20;

`[component:input-stateful-lottie:`<mark style="color:blue;">`https://assets10.lottiefiles.com/packages/lf20_vjcdl7ee.json`</mark>`]`
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
In contrast to the stateful components created with variants, remote actions can't be bound to each of the component states. Therefore, **features like favorites/like buttons aren't supported** with Lottie animations at the moment.
{% endhint %}

## Optional tag

#### Add a custom frame &#x20;

Add a custom frame to the tag that defines where the active animation is.

<mark style="color:red;">`[component:stateful-lottie:<url>:`</mark><mark style="color:blue;">`<custom-frame>`</mark><mark style="color:red;">`]`</mark>

<mark style="color:red;">`[component:input-stateful-lottie:<url>:`</mark><mark style="color:blue;">`<custom-frame>`</mark><mark style="color:red;">`]`</mark>

It's the frame where the animation changes. Setting a custom frame, sets the active animation from 0 to <`custom-frame>`, and the default animation from `<custom-frame>` to end. If no frame is specified, the animation will go from 0 to end.

In this example:\
\
The Lottie animation frame goes from 0 to 180. We will set a `<custom-frame>` of 90 as it's where we want the animation to stop.

<mark style="color:red;">`[component:input-stateful-lottie:<url>:`</mark><mark style="color:blue;">`90`</mark><mark style="color:red;">`]`</mark>

The animation plays as follows:\
To enable, on tap, the animation plays from 0 to 90,\
To disable, on tap, the animation plays from 90 to end.

<figure><img src="/files/mzxIKq4frXdQsM0FYqh4" alt=""><figcaption></figcaption></figure>

## How to add the tag

Check our LottieFile guide to see how to add Lottie URLs.&#x20;

{% embed url="<https://docs.bravostudio.app/bravo-tags/interactive-component/component-lottie#option-1-figma-only>" %}

## :floppy\_disk: Example files

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1217802397157289523>" %}


# Flexible text (Flexo)

The text box will expand down to fit the content connected via API.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag creates a flexible text box. It will expand according to the content connected from your Data Library.

**📍 Where to add the tag:** A text layer

```
[flexo]
```

![](/files/-MhsWWEL42A4Xu2gVrWx)

{% hint style="info" %}
**Important:**

* The \[flexo] element must be the bottom-most element of the container it is in.&#x20;
* You can only have one flexo text per container.&#x20;
* Top bar containers do not support flexo texts.
  {% endhint %}

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   1\. **Copy & paste** the tag into the layer name of the **text box** you want to be flexible.

![](/files/-MhsZCuVB_-4WDKp7X74)

&#x20;   2\. If you have anything below that text box, create a separate container.

![](/files/-MhsZmeSCj46CRriv519)

&#x20;   4\. Import the design file into Bravo.

&#x20;   5\. Set up your **binding** as usual, select the text box layer and match it with the data record of the text content. You can use the example request below to get sample data.

**Example data**: <https://example-data.draftbit.com/product_reviews?_limit=5>

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% @figma/embed fileId="dedkxpF23DnniDkjZnqehd" nodeId="226:0" url="<https://www.figma.com/file/dedkxpF23DnniDkjZnqehd/Bravo-Sample%3A-Bravo-Tags?node-id=226%3A0>" %}


# Zoomable image

Makes an image zoomable with pinch gesture.

## 👉 **The Tag** <a href="#the-tag" id="the-tag"></a>

This tag adds a zoomable property to an image, so users can zoom in and out with a pinch gesture.

{% hint style="warning" %}
At the moment, this feature is supported **only on Figma design files**. It will be supported on Adobe XD in the future.
{% endhint %}

**📍 Where to add the tag:** An image layer.

```
[component:imagezoom]
```

![](/files/KqkcpyikzqGFzWmV225R)

## 🏷️ **How to add the tag** <a href="#how-to-add-the-tag" id="how-to-add-the-tag"></a>

&#x20;   1\. **Copy** the tag.

&#x20;   2\. **Paste** the tag into the layer name of an **image component**.

![](/files/0meDl8mAgSA6KMqeH30t)

&#x20;   3\. Import to **Bravo Studio** & preview on **Bravo Vision** 🚀 (If you imported the app before, you just need to press the button Update in ***Bravo Studio*** to see the changes)

## 💾 Example files <a href="#example-files" id="example-files"></a>

Duplicate the files below to see how to set it up!

{% embed url="<https://www.figma.com/community/file/1030830462731458065/Bravo-Sample%3A-Zoomable-Images>" %}




---

[Next Page](/llms-full.txt/1)

