DSL syntax

Screens are defined using the Spark DSL inside a dala do ... end block. UI components are declared as nested entities with keyword props:

defmodule MyApp.HomeScreen do
  use Dala.Spark.Dsl

  dala do
    attribute :count, :integer, default: 0

    screen name: :home do
      column padding: :space_md, gap: :space_sm do
        text "Hello", text_size: :xl
        button "Save", on_tap: :save
      end
    end
  end

  def handle_event(:save, _params, socket) do
    {:noreply, socket}
  end
end

You can also build component trees as plain maps — useful when constructing UI programmatically:

%{
  type:     :column,
  props:    %{padding: 16},
  children: [
    %{type: :text,   props: %{text: "Hello", text_size: :xl}, children: []},
    %{type: :button, props: %{text: "Save",  on_tap: {self(), :save}}, children: []}
  ]
}

The two styles are fully interchangeable — you can mix them freely in the same render/1 function.


Dala.Renderer serialises the component tree to binary via the custom binary protocol and passes it to the native side in a single NIF call. Compose (Android) and SwiftUI (iOS) handle diffing and rendering.

Prop values

Props accept:

  • Integers and floats — used as-is (dp on Android, pt on iOS)
  • Strings — used as-is
  • Booleans — used as-is
  • Color atoms (:primary, :blue_500, etc.) — resolved via the active theme and the base palette to ARGB integers. See Theming.
  • Spacing tokens (:space_xs, :space_sm, :space_md, :space_lg, :space_xl) — scaled by theme.space_scale and resolved to integers.
  • Radius tokens (:radius_sm, :radius_md, :radius_lg, :radius_pill) — resolved to integers from the active theme.
  • Text size tokens (:xs, :sm, :base, :lg, :xl, :2xl, :3xl, :4xl, :5xl, :6xl) — scaled by theme.type_scale and resolved to floats.

Platform-specific props

Wrap props in :ios or :android to apply them only on that platform:

column padding: 12, ios: [padding: 20] do
  text "Content"
end

Layout components

:column

Stacks children vertically (VStack equivalent).

PropTypeDescription
paddingnumber / tokenUniform padding
padding_top, padding_bottom, padding_left, padding_rightnumber / tokenPer-side padding
gapnumber / tokenSpace between children
backgroundcolorBackground color
border_color, border_widthcolor, numberBorder styling
corner_radiusnumber / tokenRounded corners
fill_widthbooleanStretch to fill available width (default true)
width, heightnumberExplicit dimensions
alignment:start / :center / :endCross-axis alignment of children
justify:start / :center / :end / :space_betweenMain-axis distribution
on_tap, on_long_press, on_double_tap, on_swipe*{pid, tag}Gesture handlers
accessibility_idatomTest identifier
column padding: :space_md, gap: :space_sm, alignment: :center do
  text "Title"
  text "Subtitle"
end

:row

Lays out children horizontally (HStack equivalent).

PropTypeDescription
paddingnumber / tokenUniform padding
padding_top, padding_bottom, padding_left, padding_rightnumber / tokenPer-side padding
gapnumber / tokenSpace between children
backgroundcolorBackground color
border_color, border_widthcolor, numberBorder styling
corner_radiusnumber / tokenRounded corners
fill_widthbooleanStretch to fill available width
width, heightnumberExplicit dimensions
alignment:start / :center / :endCross-axis alignment of children
justify:start / :center / :end / :space_betweenMain-axis distribution
on_tap, on_long_press, on_double_tap, on_swipe*{pid, tag}Gesture handlers
accessibility_idatomTest identifier

To distribute children evenly across a row, give each child a weight prop (analogous to flex: 1 in CSS):

row fill_width: true do
  button "Cancel", on_tap: :cancel, weight: 1, background: :surface, text_color: :on_surface
  spacer size: 8
  button "Save", on_tap: :save, weight: 1
end

:box

A stacking container (ZStack equivalent). Children are layered on top of each other. Use it for overlays, badges, and absolute positioning.

PropTypeDescription
paddingnumber / tokenUniform padding
padding_top, padding_bottom, padding_left, padding_rightnumber / tokenPer-side padding
backgroundcolorBackground color
border_color, border_widthcolor, numberBorder styling
corner_radiusnumber / tokenRounded corners
fill_widthbooleanStretch to fill available width
width, heightnumberExplicit dimensions
on_tap, on_long_press, on_double_tap, on_swipe*{pid, tag}Gesture handlers
accessibility_idatomTest identifier
box background: :surface, padding: :space_md, corner_radius: :radius_md do
  text "Card content"
end

:scroll

A scrolling container (ScrollView equivalent).

PropTypeDescription
horizontalbooleanEnable horizontal scrolling (default false)
show_indicatorbooleanShow scroll indicator (default true)
on_end_reached{pid, tag}Fired when scroll reaches bottom/end
on_scroll{pid, tag}Fired during scrolling with scroll position
paddingnumber / tokenPadding inside the scroll area
backgroundcolorBackground color
scroll padding: :space_md do
  text "Long content..."
end

:spacer

Inserts fixed space in a row or column, or fills available space when no size is given.

PropTypeDescription
sizenumberFixed size in dp/pt. Omit to fill remaining space.
# Fixed gap:
spacer size: 16

# Push children to opposite ends of a row:
row do
  text "Left"
  spacer
  text "Right"
end

:safe_area

Renders children within safe area boundaries (avoiding notches, status bar, etc.).

safe_area do
  column padding: :space_md do
    text "Safe content"
  end
end

:pressable

A pressable wrapper. Makes any child tappable.

PropTypeDescription
on_press{pid, tag}Fired when pressed
on_long_press{pid, tag}Fired on long press
pressable on_press: {self(), :card_tapped} do
  text "Tap me"
end

List components

:list

A platform-native scrolling list optimised for rendering many rows efficiently. Prefer this over :scroll + :column for any list of more than ~20 items.

PropTypeDescription
idatomList identifier for selection events (required)
datalistData items (supports @ref syntax)
on_end_reached{pid, tag}Event handler when list reaches end
scrollbooleanEnable scrolling (default true)
list :my_list, data: @items, on_end_reached: :load_more

Content components

:text

Displays a string.

PropTypeDescription
textstringThe text to display (required, positional arg)
text_sizenumber / tokenFont size
text_colorcolorText color
font_weight"regular" / "medium" / "semibold" / "bold" / "light" / "thin"Font weight
font_familystringCustom font family name (nil = system font)
text_align:left / :center / :rightHorizontal alignment
italicbooleanItalic style
line_heightfloatLine height multiplier (e.g. 1.5 for 150%)
letter_spacingfloatExtra letter spacing in pt
padding, padding_top, padding_right, padding_bottom, padding_leftnumber / tokenPadding
backgroundcolorBackground color
corner_radiusnumber / tokenRounded corners
fill_widthbooleanStretch to fill parent width
on_tap, on_long_press, on_double_tap{pid, tag}Gesture handlers
accessibility_idatomTest identifier
text "Hello, world!"
text "Count: @count", text_size: :xl, text_color: :on_surface

:button

A tappable button. Has sensible defaults injected by the renderer (primary background, on_primary text, medium radius, fill width).

PropTypeDescription
textstringButton label (required). Also accepts :title for backward compatibility.
on_tap{pid, tag}Tap handler. Delivers event to handle_event/3.
disabledbooleanDisable tap interaction
variant:filled / :filled_tonal / :outlined / :elevated / :textButton style variant (default :filled)
iconstringIcon name displayed before the label
elevationfloatShadow depth for elevated variant
backgroundcolorBackground color (default :primary)
text_colorcolorLabel color (default :on_primary)
text_sizenumber / tokenFont size (default :base)
font_weightstringFont weight (default "medium")
padding, padding_top, padding_right, padding_bottom, padding_leftnumber / tokenPadding
corner_radiusnumber / tokenCorner radius (default :radius_md)
fill_widthbooleanFill available width (default true)
accessibility_idatomTest identifier
button "Save", on_tap: :save
button "Cancel", on_tap: :cancel, background: :surface, text_color: :on_surface
button "Edit", on_tap: :edit, variant: :outlined, icon: "edit"
button "Delete", on_tap: :delete, variant: :text, text_color: :error

:text_field

An editable text input. Has defaults injected by the renderer (surface_raised background, border, small radius).

PropTypeDescription
textstringCurrent text (controlled)
placeholderstringHint text when empty
on_change{pid, tag}Fires as the user types. Delivers {:change, tag, value}.
on_submit{pid, tag}Fires on keyboard return.
on_focus{pid, tag}Fires when the field gains focus.
on_blur{pid, tag}Fires when the field loses focus.
on_compose{pid, tag}IME composition events (CJK, etc.)
keyboard_type:default / :number / :decimal / :email / :phone / :urlKeyboard variant
return_key:done / :next / :go / :search / :sendReturn key type
securebooleanMask input (password field)
max_lengthintegerMaximum character count
auto_capitalize:none / :sentences / :words / :charactersAuto-capitalization behaviour
auto_correctbooleanEnable/disable auto-correct
min_linesintegerMinimum visible lines
max_linesintegerMaximum visible lines (nil = unlimited)
text_colorcolorInput text color (default :on_surface)
text_sizenumber / tokenFont size
backgroundcolorBackground (default :surface_raised)
paddingnumber / tokenPadding
corner_radiusnumber / tokenCorner radius
accessibility_idatomTest identifier
text_field placeholder: "Enter name", on_change: :name_changed
text_field placeholder: "Password", secure: true, on_change: :password_changed
text_field placeholder: "Email", keyboard_type: :email, return_key: :next, on_submit: :next_field

:icon

Displays a platform-native icon. Logical icon names are resolved to SF Symbols on iOS and Material Symbols on Android.

PropTypeDescription
namestringLogical icon name or raw identifier (required)
text_sizenumberGlyph size in sp
text_colorcolorGlyph tint color
paddingnumber / tokenPadding around icon
backgroundcolorBackground color
on_tap, on_long_press{pid, tag}Gesture handlers
accessibility_idatomTest identifier (also used as accessibility label)

Logical icon names: settings, back, forward, close, add, remove, edit, check, chevron_right, chevron_left, chevron_up, chevron_down, info, warning, error, search, trash, share, more, menu, refresh, favorite, favorite_filled, star, star_filled, user, home

icon name: "settings", text_size: 24, text_color: :on_surface
icon name: "chevron_right", on_tap: {self(), :navigate}

:divider

A horizontal or vertical divider line.

PropTypeDescription
thicknessfloatLine thickness in pt (default 1.0)
colorcolorDivider color (default :border)
paddingnumber / tokenPadding around the divider
divider
divider thickness: 2, color: :primary

:image

Displays an image from a URL or local asset.

PropTypeDescription
srcstringURL or local asset name (required)
resize_mode:cover / :contain / :stretch / :repeatResize mode (default :cover)
width, heightnumberDimensions in dp/pt; omit to auto-size
corner_radiusnumber / tokenRounded corners
placeholder_colorcolorColor shown while loading
on_error{pid, tag}Fired when image fails to load
on_load{pid, tag}Fired when image finishes loading
accessibility_idatomTest identifier
image src: "https://example.com/photo.jpg", resize_mode: :cover, corner_radius: 12

:video

An inline video player.

PropTypeDescription
srcstringVideo URL (required)
autoplaybooleanStart playing immediately (default false)
loopbooleanLoop playback (default false)
controlsbooleanShow playback controls (default true)
width, heightnumberDimensions in dp/pt; omit to fill parent
video src: "https://example.com/clip.mp4", autoplay: true, loop: true

:progress_bar

A progress bar (determinate or indeterminate).

PropTypeDescription
progressfloatCurrent progress 0.0–1.0 (default 0.0)
indeterminatebooleanShow indeterminate spinner (default false)
colorcolorProgress bar color
progress_bar progress: 0.7, color: :primary
progress_bar indeterminate: true

:activity_indicator

A circular loading spinner.

PropTypeDescription
size:small / :largeSpinner size (default :small)
colorcolorSpinner color (default theme primary)
animatingbooleanWhether spinner is animating (default true)
activity_indicator size: :large, color: :primary

:toggle

A boolean switch. Delivers {:change, tag, value} to handle_event/3 where value is true or false.

PropTypeDescription
valuebooleanCurrent checked state
on_change{pid, tag}Fires when toggled. Delivers {:change, tag, bool}.
textstringLabel text displayed beside the toggle
track_colorcolorColor when switch is on
thumb_colorcolorColor of the draggable thumb
accessibility_idatomTest identifier
toggle value: true, on_change: {self(), :notifications_toggled}, text: "Enable notifications"

def handle_event({:change, :notifications_toggled, enabled}, _params, socket) do
  {:noreply, Dala.Socket.assign(socket, :notifications_on, enabled)}
end

:slider

A continuous value input. Delivers {:change, tag, value} to handle_event/3 where value is a float.

PropTypeDescription
valuefloatCurrent value (default 0.0)
min_valuefloatMinimum value (default 0.0)
max_valuefloatMaximum value (default 1.0)
on_change{pid, tag}Fires as the user drags. Delivers {:change, tag, float}.
colorcolorTrack and thumb color
accessibility_idatomTest identifier
slider value: 0.5, min_value: 0.0, max_value: 1.0, on_change: :volume_changed

def handle_event({:change, :volume_changed, value}, _params, socket) do
  {:noreply, Dala.Socket.assign(socket, :volume, value)}
end

:tab_bar

A tab navigation bar.

PropTypeDescription
tabslist of mapsEach map has :id, :label, and optional :icon
active_tabstringThe id of the currently selected tab
on_tab_select{pid, tag}Fired with selected tab id string
accessibility_idatomTest identifier
tab_bar(
  tabs: [
    %{id: "home", label: "Home", icon: "home"},
    %{id: "settings", label: "Settings", icon: "settings"}
  ],
  active_tab: "home",
  on_tab_select: {self(), :tab_changed}
)

:refresh_control

Pull-to-refresh control for scroll views.

PropTypeDescription
on_refresh{pid, tag}Fired when user pulls to refresh
refreshingbooleanTrue while refresh is in progress
tint_colorcolorColor of the refresh spinner
scroll padding: :space_md do
  refresh_control on_refresh: {self(), :refresh}, refreshing: @refreshing
  # content...
end

Selection components

:checkbox

A checkbox for selecting one or more items from a list. Maps to Checkbox on Compose and Toggle on SwiftUI.

PropTypeDescription
valuebooleanCurrent checked state
on_change{pid, tag}Fires when toggled. Delivers {:change, tag, bool}.
labelstringLabel text displayed beside the checkbox
colorcolorCheckbox tint color
enabledbooleanWhether the checkbox is interactive (default true)
disabledbooleanDisable the checkbox
text_colorcolorText color token
text_sizeanyFont size
accessibility_idatomTest identifier
checkbox value: true, on_change: {self(), :agree_toggled}, label: "I agree"

checkbox value: false, label: "Accept terms", color: :primary, enabled: false

:radio

A radio button within a group. Only one radio in a group can be selected. Maps to RadioButton on Compose and Toggle with style on SwiftUI.

PropTypeDescription
selectedbooleanWhether this radio is selected
on_select{pid, tag}Fired when this radio is selected
labelstringLabel text displayed beside the radio
groupstringRadio group name (radios in the same group are mutually exclusive)
enabledbooleanWhether the radio is interactive (default true)
colorcolorRadio tint color
disabledbooleanDisable the radio
text_colorcolorText color token
text_sizeanyFont size
accessibility_idatomTest identifier
radio selected: true, on_select: {self(), :option_a}, label: "Option A", group: "choices"

:chip

A compact Material Design chip. Maps to FilterChip, InputChip, etc. on Compose.

PropTypeDescription
labelstringChip text (required)
variant:assist / :filter / :input / :suggestionChip style variant
selectedbooleanSelected state (for filter chips)
on_tap{pid, tag}Fired when chip is tapped
iconstringIcon name displayed before the label
on_remove{pid, tag}Fired when remove icon is tapped (input chips)
enabledbooleanWhether the chip is interactive (default true)
disabledbooleanDisable the chip
text_colorcolorText color token
text_sizeanyFont size
backgroundcolorBackground color token
corner_radiusintegerRounded corner radius
accessibility_idatomTest identifier
chip label: "Filter", variant: :filter, selected: true, on_tap: {self(), :chip_tapped}
chip label: "Tag", variant: :input, on_remove: {self(), :tag_removed}

A horizontally scrolling carousel of items. Maps to HorizontalPager on Compose.

PropTypeDescription
dataenumerableItems to render
idatomCarousel identifier
on_page_change{pid, tag}Fired with new page index on swipe
loopbooleanEnable infinite looping (default false)
autoplaybooleanEnable autoplay (default false)
autoplay_intervalintegerAutoplay interval in ms
peekfloatPeek width for adjacent items
accessibility_idatomTest identifier
carousel id: :photo_carousel, data: @photos, on_page_change: {self(), :page_changed}

Communication components

:snackbar

A transient message bar with an optional action. Maps to Snackbar on Compose.

PropTypeDescription
messagestringThe message text (required)
action_labelstringLabel for the optional action button
on_action{pid, tag}Fired when the action button is tapped
duration:short / :longDisplay duration
visiblebooleanWhether the snackbar is shown (default true)
text_colorcolorText color token
backgroundcolorBackground color token
accessibility_idatomTest identifier
snackbar message: "Item deleted", action_label: "Undo", on_action: {self(), :undo}

:tooltip

Shows a tooltip over its children. Maps to Tooltip on Compose and help modifier on SwiftUI.

PropTypeDescription
textstringTooltip text (required)
position:top / :bottom / :left / :rightTooltip position
visiblebooleanWhether the tooltip is shown
delayintegerShow delay in ms
accessibility_idatomTest identifier
tooltip text: "Save changes", position: :top do
  icon name: "save"
end

Action components

:fab

A Floating Action Button. Maps to FloatingActionButton on Compose.

PropTypeDescription
iconstringIcon name (required)
on_tap{pid, tag}Fired when FAB is tapped
textstringOptional label for extended FAB
backgroundcolorBackground color (default :primary)
colorcolorIcon color (default :on_primary)
corner_radiusnumber / tokenCorner radius
elevationfloatShadow depth
accessibility_idatomTest identifier
fab icon: "add", on_tap: {self(), :add_item}
fab icon: "edit", text: "Compose", on_tap: {self(), :compose}

:icon_button

A clickable icon button. Maps to IconButton on Compose.

PropTypeDescription
iconstringIcon name (required)
on_tap{pid, tag}Fired when button is tapped
selectedbooleanToggle state for toggle icon buttons
enabledbooleanWhether the button is interactive (default true)
colorcolorIcon color
backgroundcolorBackground color
sizeanyButton size
disabledbooleanDisable the button
accessibility_idatomTest identifier
icon_button icon: "favorite", on_tap: {self(), :favorite_tapped}
icon_button icon: "bookmark", selected: true, enabled: false

:segmented_button

A segmented control with multiple segments. Maps to SegmentedButton on Compose.

PropTypeDescription
segmentslist of mapsEach map has :id, :label, and optional :icon
selectedstringThe id of the currently selected segment
on_select{pid, tag}Fired with selected segment id
text_colorcolorText color token
backgroundcolorBackground color token
accessibility_idatomTest identifier
segmented_button(
  segments: [
    %{id: "day", label: "Day"},
    %{id: "week", label: "Week"},
    %{id: "month", label: "Month"}
  ],
  selected: "week",
  on_select: {self(), :range_changed}
)

:app_bar

A top app bar with title and action icons. Maps to TopAppBar on Compose.

PropTypeDescription
titlestringApp bar title
leading_iconstringIcon name for the leading navigation icon
on_leading{pid, tag}Fired when leading icon is tapped
trailing_actionslist of mapsEach map has :icon and :on_tap
backgroundcolorBackground color
text_colorcolorTitle and icon color
elevationfloatShadow depth
accessibility_idatomTest identifier
app_bar(
  title: "My App",
  leading_icon: "back",
  on_leading: {self(), :back_pressed},
  trailing_actions: [%{icon: "search", on_tap: {self(), :search}}]
)

A bottom navigation bar. Maps to NavigationBar on Compose.

PropTypeDescription
itemslist of mapsEach map has :id, :label, and :icon
activestringId of the currently active item
on_select{pid, tag}Fired with selected item id
accessibility_idatomTest identifier
nav_bar(
  items: [
    %{id: "home", label: "Home", icon: "home"},
    %{id: "profile", label: "Profile", icon: "user"}
  ],
  active: "home",
  on_select: {self(), :tab_changed}
)

A side navigation drawer. Maps to ModalNavigationDrawer on Compose.

PropTypeDescription
visiblebooleanWhether the drawer is shown
on_dismiss{pid, tag}Fired when the drawer is dismissed
itemslist of mapsEach map has :id, :label, and :icon
activestringId of the currently active item
on_select{pid, tag}Fired with selected item id
headerstringOptional header text at the top
backgroundcolorBackground color token
accessibility_idatomTest identifier
nav_drawer(
  visible: true,
  on_dismiss: {self(), :drawer_dismissed},
  items: [%{id: "home", label: "Home", icon: "home"}],
  active: "home",
  on_select: {self(), :nav_changed}
)

A side navigation rail (for tablets/desktop). Maps to NavigationRail on Compose.

PropTypeDescription
itemslist of mapsEach map has :id, :label, and :icon
activestringId of the currently active item
on_select{pid, tag}Fired with selected item id
text_colorcolorText color token
backgroundcolorBackground color token
accessibility_idatomTest identifier
nav_rail(
  items: [
    %{id: "home", label: "Home", icon: "home"},
    %{id: "settings", label: "Settings", icon: "settings"}
  ],
  active: "home",
  on_select: {self(), :rail_changed}
)

A popup menu with selectable items. Maps to DropdownMenu on Compose.

PropTypeDescription
itemslist of mapsEach map has :label, :action (atom), and optional :icon
visiblebooleanWhether the menu is shown
on_dismiss{pid, tag}Fired when the menu is dismissed
on_select{pid, tag}Fired with selected item's action atom
text_colorcolorText color token
backgroundcolorBackground color token
accessibility_idatomTest identifier
menu(
  items: [%{label: "Edit", action: :edit}, %{label: "Delete", action: :delete}],
  visible: true,
  on_select: {self(), :menu_selected}
)

:date_picker

A date selection dialog. Maps to DatePicker on Compose and UIDatePicker on SwiftUI.

PropTypeDescription
visiblebooleanWhether the picker is shown
on_select{pid, tag}Fired with selected date string (ISO 8601)
on_dismiss{pid, tag}Fired when the picker is dismissed
selected_datestringInitial date in ISO 8601 format
min_datestringEarliest selectable date
max_datestringLatest selectable date
titlestringOptional title text
accessibility_idatomTest identifier
date_picker(
  visible: true,
  on_select: {self(), :date_picked},
  selected_date: "2025-01-15"
)

:time_picker

A time selection dialog. Maps to TimePicker on Compose and UIDatePicker on SwiftUI.

PropTypeDescription
visiblebooleanWhether the picker is shown
on_select{pid, tag}Fired with selected time string (HH:MM)
on_dismiss{pid, tag}Fired when the picker is dismissed
selected_timestringInitial time in HH:MM format
titlestringOptional title text
accessibility_idatomTest identifier
time_picker(
  visible: true,
  on_select: {self(), :time_picked},
  selected_time: "09:30"
)

A search input bar with placeholder and callbacks. Maps to SearchBar on Compose and UISearchBar on SwiftUI.

PropTypeDescription
placeholderstringPlaceholder text when empty
textstringCurrent search text
on_change{pid, tag}Fired on every text change
on_submit{pid, tag}Fired when search is submitted
on_focus{pid, tag}Fired when the bar gains focus
activebooleanWhether the search bar is in active/expanded state
on_tap{pid, tag}Fired when the search bar is tapped
accessibility_idatomTest identifier
search_bar(placeholder: "Search...", on_change: {self(), :search_changed}, on_submit: {self(), :search_submitted})

Event handler conventions

In DSL style, event handlers are atoms that map directly to handle_event/3 clauses:

dala do
  screen name: :home do
    button "Save", on_tap: :save
  end
end

def handle_event(:save, _params, socket) do
  {:noreply, socket}
end

Event routing

All events are delivered to the screen process via handle_event/3. Every on_tap, on_change, on_select, and similar handler sends its message directly to the screen process — regardless of how deeply the component is nested in the tree.

Handler propMessage delivered to handle_event/3
on_tap: :tag:tag
on_change: :tag{:change, :tag, value}
on_select: :tag (list){:select, :tag, index}
on_submit: :tag:tag
on_focus: :tag:tag
on_blur: :tag:tag
on_dismiss: :tag:tag
on_action: :tag:tag
on_leading: :tag:tag
on_remove: :tag:tag
on_page_change: :tag{:page_change, index}

Screen registration with Dala.App.screens/1

Register screen modules in your app's navigation/1 callback using screens/1. This validates at compile time that modules are valid Dala.Screen modules:

defmodule MyApp do
  use Dala.App

  def navigation(_platform) do
    screens([MyApp.HomeScreen, MyApp.SettingsScreen])
    stack(:home, root: MyApp.HomeScreen)
  end
end

See Navigation for full details.