XAML & Layouts
Here's the mental model for this whole phase: a page is one root layout holding controls. A screen in MAUI is a ContentPage, it holds exactly one thing - a layout - and the layout's job is to arrange the controls inside it. Controls are the leaves: labels, buttons, text boxes. Layouts are the branches that decide where those leaves sit.
The markup you write to describe this tree is XAML - an XML dialect, not a separate magic language. Every XAML element is just a C# object: write <Label Text="Hi" /> and MAUI creates a Label object with its Text property set to "Hi". The page's <x:Class> attribute names a C# partial class, and the XAML becomes part of that class at build time - it compiles down to the same C# objects you could write by hand.
📝 You can build the entire UI in C# instead of XAML -
new ContentPage { Content = new Label { Text = "Hi" } }. Most MAUI code uses XAML because a declarative tree is easier to read and tweak than nested constructor calls.
The page and its one root layout
A bare page looks like this:
What just happened: The xmlns lines map XML namespaces to MAUI's control library and to XAML's own keywords (that's where x:Class comes from). x:Class="NotesApp.MainPage" ties this file to the C# partial class MainPage in your project, and the ContentPage holds a single child - here a lone Label. A ContentPage has exactly one Content; to show more than one control, that single child has to be a layout that holds the rest.
The layouts you'll actually use
Stack layouts - children in a line
VerticalStackLayout arranges its children top to bottom; HorizontalStackLayout does it left to right - the simplest containers, great for short, linear groups.
What just happened: Three controls stacked vertically with a 12-unit gap between each (Spacing) and 20 units of breathing room around the whole group (Padding). Padding is space inside the container's edge; Spacing is the gap between children. The page has one root child (the stack), and the stack holds the three controls - the mental model in action.
Grid - rows and columns, the real workhorse
Stacks are fine for a line of controls, but real screens have structure: a header pinned at the top, a body that fills the rest, a footer that hugs the bottom. That's a Grid - it defines RowDefinitions and ColumnDefinitions, and each child says which cell it lives in with Grid.Row and Grid.Column (both default to 0).
What just happened: RowDefinitions="Auto,*,Auto" makes three rows. Auto sizes a row to exactly fit its content - the title and the button take only the height they need. * means "take all the leftover space" - the middle row stretches to fill whatever's left, exactly what you want for a scrolling list of notes. Header on top, body fills the gap, action button parked at the bottom.
💡 The sizing tokens are the whole point of
Grid.Auto= size to content.*= take the remaining space (2*takes twice the share of a plain*, so*,2*splits leftover space one-third / two-thirds). Because*rows and columns flex with the screen, the same layout looks right on a narrow phone and a wide desktop.
ScrollView - when content overflows
A ContentView or stack won't scroll on its own - if its content is taller than the screen, the overflow is clipped. Wrap it in a ScrollView and it scrolls.
<!-- ...many more controls... -->
What just happened: ScrollView takes one child (here the stack) and gives it a scrollable viewport - anything taller than the screen now scrolls instead of getting cut off. (FlexLayout and AbsoluteLayout also exist for wrap-and-flow and pixel-precise positioning, but you'll reach for them far less often - start with stacks, Grid, and ScrollView.)
Common controls and their key properties
Layouts arrange things; controls are the things. The handful you'll use constantly:
Label- displays text.Button- a tappable button with aClickedevent.Entry- single-line text input.Editor- multi-line text input (think note body).Image- shows an image from aSource.
Properties are written as XAML attributes. The ones you'll set most often:
What just happened: FontSize and TextColor style the label. HorizontalOptions (and its sibling VerticalOptions) control how a child sits in the space its parent gives it - values are Start, Center, End, and Fill; here the title is centered and the button pushed right (End). Margin="0,16,0,0" adds space outside the button (left, top, right, bottom order), nudging it down from the editor. Placeholder is the grey hint text shown in an empty Entry/Editor.
⚠️ Margin vs. Padding catches everyone once: Padding is space inside a container, before its children start. Margin is space outside a control, pushing its neighbors away. Same four-number order -
left,top,right,bottom- but opposite sides of the control's edge.
One real warning: don't nest stacks endlessly
When stacks are the only tool you know, it's tempting to build a whole screen by burying stacks inside stacks inside stacks to push things around. Resist it.
⚠️ Deeply nested stack layouts hurt performance and are miserable to maintain. Each stack measures and arranges its children, and nesting multiplies that work on every layout pass - on a scrolling list, it shows up as jank. Worse, six levels deep, nobody can tell which container owns which spacing. A Grid with a few RowDefinitions/ColumnDefinitions does the same job flat. For anything beyond a short line of controls, reach for Grid first.
Building the notes app's main page
Let's put it together into the real screen for our running notes app: a title at the top, a list area in the middle (a placeholder - the real list comes in Phase 3), and an Add button at the bottom.
<!-- Header -->
<!-- List area (placeholder until Phase 3) -->
<!-- Action -->
What just happened: One ContentPage, one root Grid, three children - exactly the mental model. The Auto,*,Auto rows give a fixed-height header, a flexible body that fills the screen (room to grow and scroll once real notes arrive), and a fixed-height button at the bottom. The body label is a placeholder; Phase 3 swaps it for a CollectionView bound to actual data. HorizontalOptions="Fill" on the button stretches it the full width. Run this and you've got the skeleton of the whole app - built with one flat Grid instead of a tangle of stacks.
Recap
- A page is one root layout holding controls -
ContentPagehas exactly oneContent, and to show several controls that one child must be a layout. - XAML is C# objects. Each element constructs an object and each attribute sets a property;
x:Classties the file to a C# partial class. - Stack layouts line children up (
Spacingbetween,Paddingaround);Gridplaces children in rows/columns usingGrid.Row/Grid.Column, withAuto= size-to-content and*= take remaining space;ScrollViewlets overflow scroll. - Common controls -
Label,Button,Entry,Editor,Image- are styled with attributes likeFontSize,TextColor,HorizontalOptions,Margin, andPadding. - Prefer
Gridover deeply nested stacks for any non-trivial screen - it's faster and far more maintainable - and lean on*sizing so one layout works across phone, tablet, and desktop.
Quick check
[
{
"q": "In a Grid with RowDefinitions=\"Auto,*,Auto\", what does the middle \"*\" row do?",
"choices": ["Sizes itself to exactly fit its content", "Takes up all the leftover space after the Auto rows", "Is hidden until content is added", "Forces a fixed height of 1 unit"],
"answer": 1,
"explain": "\"*\" means take the remaining space. Combined with Auto rows above and below, it gives a flexible body between a fixed header and footer."
},
{
"q": "How many direct children can a ContentPage's Content hold?",
"choices": ["As many as you like", "Exactly one (usually a layout)", "Up to ten", "Only controls, never layouts"],
"answer": 1,
"explain": "A ContentPage holds one Content. To show multiple controls, that single child must be a layout that holds the rest."
},
{
"q": "Why prefer a Grid over deeply nested stack layouts for a non-trivial screen?",
"choices": ["Grids can't be styled, so they're simpler", "Nested stacks hurt performance and maintainability; a flat Grid does the same job", "Stacks don't work on iOS", "Grids are the only layout that supports Padding"],
"answer": 1,
"explain": "Each nested stack adds measure/arrange work and obscures which container owns what. A Grid places everything flat by row and column - faster and clearer."
}
]
Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.
Check your understanding 3 questions
1. In a Grid with RowDefinitions="Auto,*,Auto", what does the middle "*" row do?
2. How many direct children can a ContentPage's Content hold?
3. Why prefer a Grid over deeply nested stack layouts for a non-trivial screen?