---
title: Responsive Design
hide_title: true
---
import useBaseUrl from '@docusaurus/useBaseUrl';
import CopyToClipboardButton from '/src/components/copytoclipboardbutton';
# Responsive Design
## What you will learn in this guide
In this guide we will take a look at a couple of different techiques you can use to build responsive UIs in your Noodl app.
## Simple grids with the Columns node
One of the most common situations where responsiveness is needed is in grids of items. The easiest way to create responsive grids is through the **Min Column Width** input on the **Columns** node. This approach works best when dealing with grids where the items should have the same width, like cards or images. Let's focus on the two key inputs for this technique:
### Layout String
A layout string is simply a string of numbers with spaces between them. Every number represents a fraction of the full container width and is converted to a column. A **Columns** node with the layout string `1 2 1` that contains 5 children will be rendered like this:

### Min Column Width
The **Min Column Width** sets the minimum width for each column. It first checks if the columns can fit based on the provided **Layout String**. If the container cannot hold the columns at their minimum width, the layout will automatically fold into a grid with fewer columns.
> Make sure the children you pass are set to a width of `100%` of their parent.
### Strategy
The most common way of using this method is to set the **Layout String** to the maximum amount of columns we want the layout to have. Then set the **Min Column Width** to the value where the grid items starts looking broken. This will produce a result like this:
## Media Query prefab and States node
The techique above works great for grids that are even, but what if we have a more advanced layout? Maybe we need to add more padding, change the font size or even change the **Layout String** altogether?
For this we can use the **[Media Query](/library/prefabs/media-query/)** prefab, together with the **[States](/nodes/utilities/logic/states/)** node. It's a good idea to read the documentation for these, but for now you'll get a quick introduction. Let's begin by understanding the **States** node.
The **States** node is a really useful and flexible tool in Noodl. In this guide however, we'll only need to focus on its most basic features. In essence, it allows us to set up different `Values` that hold different data depending on the `State` of the node. This can be found in the three main sections of the **States** node's property panel. Let's look at an example.
### With properties
First we setup the different `States` we want. These can be named anything, but since we are working with screen size responsiveness, let's make it descriptive:

Now we can create the `Values` we want this node to output. In this example we will be working with a bottom margin for a header, so let's name it that:

Now we can fill in what data we want the `Value` to output for the different states:

Now that we have the states set up, we need to determine when a specific state is active. The **Media Query** prefab's **Match Media Query** component checks the active screen size breakpoint and outputs `true` or `false` based on matches. We can use these outputs to trigger our defined states:

> This method can be used with any trigger, to set any value - even text in buttons!
### With Columns
This technique becomes really powerful when we use it to send different **Layout Strings** to the **Columns** node. Here's an example where we change the layout between `1 1 2 1`, `2 1 1` and `1 2` depending on viewport size:
### With Mounted
Responsive layouts can vary a lot at different screen sizes. For example, header menus can look _totally_ different on desktop and mobile, making it hard (or messy) to use the above technique. For this we can use the breakpoint outputs on **Match Media Query** and send them to the `Mounted` input on any visual node, to show/hide different parts of our visual tree:

In the case above, we have created two components that have a `Mounted` in their **Comonent Inputs** node. That value is being passed to the `Mounted` input on the root node of the component:

## Container queries
So far we've been making our UI responsive by checking the size of the screen. This is the most traditional approach, and it still works well. However, as app architecture and design has evolved, the industry has found a need for more hands-off component systems that work well in any context.
One solution to this is a concept called **Container Queries**. Here we check for the size of the component in question, and set the responsiveness based on that (instead of the viewport).
Here's a very basic example using a **Function** node to check a components witdth and set different `Layout Strings`:
300) {\n Outputs.GreaterThan300()\n} else {\n Outputs.LessThan300()\n}"},"ports":[],"children":[],"metadata":{"merge":{"soureCodePorts":["functionScript"]}}}],"connections":[{"fromId":"0f6a75fa-864e-a6b8-85b9-cc79d0745636","fromProperty":"Layout String","toId":"9d143294-1d35-6701-b33e-2be10c58abb4","toProperty":"layoutString"},{"fromId":"4b33f8cd-3c7d-d5fe-decd-7c4c6663d926","fromProperty":"boundingWidth","toId":"c872f350-1079-b6e6-0b09-2d1944a2730d","toProperty":"in-Width"},{"fromId":"c872f350-1079-b6e6-0b09-2d1944a2730d","fromProperty":"out-GreaterThan300","toId":"0f6a75fa-864e-a6b8-85b9-cc79d0745636","toProperty":"to-Is Double Column"},{"fromId":"c872f350-1079-b6e6-0b09-2d1944a2730d","fromProperty":"out-LessThan300","toId":"0f6a75fa-864e-a6b8-85b9-cc79d0745636","toProperty":"to-Is Single Column"}],"comments":[]}}
/>

Here's the code running in the function node:
```js
if (Inputs.Width > 300) {
Outputs.GreaterThan300()
} else {
Outputs.LessThan300()
}
```
We can now use this item grid everywhere, without caring if it's in a page-wide or column-narrow container. It will always render in a layout we know works.
This is great for both responsivity and reusability. Here's an example of a profile card in two different sized containers. It can be placed in any context and still look good:
300) {\n Outputs.GreaterThan300()\n} else {\n Outputs.LessThan300()\n}"},"ports":[],"children":[],"metadata":{"merge":{"soureCodePorts":["functionScript"]}}}],"connections":[{"fromId":"4c080ef9-5e6f-f8fa-4008-2fabb4652eb0","fromProperty":"Layout String","toId":"d0629fbe-04de-2225-3179-86a22ed1e074","toProperty":"layoutString"},{"fromId":"d3d29aa3-87d2-361a-cb40-c77fd2048da4","fromProperty":"boundingWidth","toId":"8f070f26-c163-ad05-1ab0-9f09ca009d1c","toProperty":"in-Width"},{"fromId":"8f070f26-c163-ad05-1ab0-9f09ca009d1c","fromProperty":"out-GreaterThan300","toId":"4c080ef9-5e6f-f8fa-4008-2fabb4652eb0","toProperty":"to-Double Column"},{"fromId":"8f070f26-c163-ad05-1ab0-9f09ca009d1c","fromProperty":"out-LessThan300","toId":"4c080ef9-5e6f-f8fa-4008-2fabb4652eb0","toProperty":"to-Single Column"}],"comments":[]}}
/>

### Generating checks with AI
In the container query example, we used a simple if-statement in a **Function** node to check the size. It worked great because we only needed to switch between two states when the container was larger or smaller than 300px.
This if-statement can be extended to output different signals. This can either be written by hand, or generated by the AI assistant, using the `/Function` command:

(Note that the AI assumed that we wanted to use this function with a screen width. Since we asked for a `Width` input, that doesn't matter. It will work with any number sent to it.)
## Limiter component
So far we've mainly talked about making content fit smaller screens. But it's also important to limit the content when the screen gets bigger. To do this, we can use a Limiter component. The basic version uses two **Group** nodes: one for centering and padding, and another with a `max-width` to hold the content:

This will provide the following result:
This component will allow us to keep the content size and spacing consistent across the app.
A more advanced and configurable version of this component can be copied by pressing the "Copy nodes" button below:

It features the following options in the property panel:

## Get building!
Now you know all of the techniques we use when building responsive designs. However, Noodl is flexible, and we always learn new things from the community. If you have any tips and tricks that you use, but that havent been touched upon here and feel like sharing it, feel free to hop on in on the [Discord server](https://discord.com/invite/23xU2hYrSJ). The community is always happy to hear your ideas and feedback.
Happy Noodling!