View Source View Index
Accessibility
<ScaledMetric>
Tracks changed to the dynamic type size in the current context.
<ScaledMetric phx-change="scaled-value-changed" value={100} relativeTo="largeTitle">
<Image systemName="heart" class="resizable frame-attr" frame={@scaled_value}>
</ScaledMetric>
defmodule MyAppWeb.AccessibilityLive do
def handle_event("scaled-value-changed", scaled_value, socket) do
{:noreply, assign(socket, scaled_value: scaled_value)}
end
end
Buttons
<Button>
<Button>
, sends events when tapped.
<Button phx-click="my_event" phx-value-extra="more info">Click Me!</Button>
def handle_event("my_event", %{ "extra" => extra }, socket) do
{:noreply, assign(socket, value: extra)}
end
<PasteButton>
Sends an event with the clipboard’s contents when tapped.
<PasteButton phx-click="my_event" />
def handle_event("my_event", %{ "value" => value }, socket) do
{:noreply, assign(socket, :pasted_value, hd(value))}
end
Collection Containers
<List>
Presents rows of elements.
<List>
<%= for sport <- @sports do %>
<Text id={sport.id}><%= sport.name %></Text>
<% end %>
</List>
<EditButton />
<List> ... </List>
<List selection={@selected_sports} phx-change="selection-changed">
...
</List>
<List phx-delete="on_delete">
...
</List>
defmodule MyAppWeb.SportsLive do
def handle_event("on_delete", %{ "index" => index }, socket) do
{:noreply, assign(socket, :items, List.delete_at(socket.assigns.items, index))}
end
end
<List phx-move="on_move">
...
</List>
defmodule MyAppWeb.SportsLive do
def handle_event("on_move", %{ "index" => index, "destination" => destination }, socket) do
{element, list} = List.pop_at(socket.assigns.sports, index)
moved = List.insert_at(list, (if destination > index, do: destination - 1, else: destination), element)
{:noreply, assign(socket, :sports, moved)}
end
end
<Section>
Groups elements in a container.
<Section>
<Text>Item #1</Text>
...
</Section>
<Section>
<Text>Item #1</Text>
...
</Section>
<Section>
<Text template={:header}>Group #1</Text>
<Text template={:content}>Item #1</Text>
<Text template={:footer}>The first group ends here</Text>
</Section>
<Section>
<Text template={:header}>Group #2</Text>
<Text template={:content}>Item #1</Text>
<Text template={:footer}>The second group ends here</Text>
</Section>
<Section collapsible>
...
</Section>
<Table>
A container organized by rows and columns.
<Table>
<Group template={:columns}>
<TableColumn id="name">Name</TableColumn>
<TableColumn id="description">Description</TableColumn>
<TableColumn id="length">Length</TableColumn>
</Group>
<Group template={:rows}>
<TableRow id="basketball">
<Text>Basketball</Text>
<Text>Players attempt to throw a ball into an elevated basket.</Text>
<Text>48 min</Text>
</TableRow>
<TableRow id="soccer">
<Text>Soccer</Text>
<Text>Players attempt to kick a ball into a goal.</Text>
<Text>90 min</Text>
</TableRow>
<TableRow id="football">
<Text>Football</Text>
<Text>Players attempt to throw a ball into an end zone.</Text>
<Text>60 min</Text>
</TableRow>
</Group>
</Table>
<Table sortOrder={@sports_sort_order} phx-change="sort-changed">
...
<Group template={:rows}>
<%= for sport <- Enum.sort_by(
@sports,
fn sport -> sport[hd(@sports_sort_order)["id"]] end,
(if hd(@sports_sort_order)["order"], do: &</2, else: &>/2)
) do %>
<TableRow id={sport["id"]}>
<Text><%= sport["name"] %></Text>
<Text><%= sport["description"] %></Text>
<Text><%= sport["length"] %></Text>
</TableRow>
<% end %>
</Group>
</Table>
<Table selection={@selected_sports} phx-change="selection-changed">
...
</Table>
Drawing and Graphics
<ColorView>
A rectangle with a particular fill color.
<Color red={1} green={0} blue={0.5} />
<Color name="MyAppColor" opacity={0.5} />
<Color name="system-red" />
<Color name="#ff0000" />
<NamespaceContext>
Creates a namespace for child elements to use.
Forms
<Form>
A container for grouping labeled form controls in a consistent style.
<LabeledContent>
Presents an element with an associated label.
<LabeledContent>
<Text template="label">Price</Text>
<Text template="content">$100.00</Text>
</LabeledContent>
<LabeledContent value={100} format="currency" currencyCode="usd">
Price
</LabeledContent>
Grids
<Grid>
Align elements along two dimensions.
<Grid>
<GridRow>
<Text>Title</Text>
<Text>Description</Text>
</GridRow>
<GridRow>
<Text>Item #1</Text>
<Text>The first of many items.</Text>
</GridRow>
</Grid>
<GridRow>
A row of items in a grid.
<Grid>
<GridRow>
<Text>Title</Text>
<Text>Description</Text>
</GridRow>
<GridRow>
<Text>Item #1</Text>
<Text>The first of many items.</Text>
</GridRow>
</Grid>
Groups
<ControlGroup>
Visual grouping of control elements.
<ControlGroup>
<Text template={:label}>Edit Actions</Text>
<Group template={:content}>
<Button phx-click="arrange">Arrange</Button>
<Button phx-click="update">Update</Button>
<Button phx-click="remove">Remove</Button>
</Group>
</ControlGroup>
<DisclosureGroup>
An expandable section of content.
<DisclosureGroup>
<Text template={:label}>Edit Actions</Text>
<Group template={:content}>
<Button phx-click="arrange">Arrange</Button>
<Button phx-click="update">Update</Button>
<Button phx-click="remove">Remove</Button>
</Group>
</DisclosureGroup>
<DisclosureGroup isExpanded={@actions_open} phx-change="actions-group-changed">
...
</DisclosureGroup>
<Group>
A collection of elements.
<Group class="tint-orange">
<Button>Orange Button</Button>
<Toggle>Orange Toggle</Toggle>
<Slider>Orange Slider</Slider>
</Group>
<VStack>
<Group>
<Text>1</Text>
<Text>2</Text>
<Text>3</Text>
<Text>4</Text>
<Text>5</Text>
<Text>6</Text>
<Text>7</Text>
<Text>8</Text>
<Text>9</Text>
<Text>10</Text>
</Group>
<Text>11</Text>
</VStack>
<GroupBox>
Visual grouping of elements.
<GroupBox>
<Text template={:label}>Edit Actions</Text>
<Group template={:content}>
<Button phx-click="arrange">Arrange</Button>
<Button phx-click="update">Update</Button>
<Button phx-click="remove">Remove</Button>
</Group>
</GroupBox>
<GroupBox title="Edit Actions">
<Button phx-click="arrange">Arrange</Button>
<Button phx-click="update">Update</Button>
<Button phx-click="remove">Remove</Button>
</GroupBox>
Images
<AsyncImage>
Displays an image asynchronously loaded from a URL.
<AsyncImage url="http://localhost:4000/example.jpg" />
<ImageView>
Displays an image.
<Image name="MyCustomImage" />
<Image systemName="chart.bar.fill" variableValue={0.3} />
<Image systemName="chart.bar.fill" variableValue={0.6} />
<Image systemName="chart.bar.fill" variableValue={1.0} />
<Image name="landscape">
Mountain landscape with a lake in the foreground
</Image>
"heart" do
resizable()
symbolRenderingMode(.multicolor)
end
<Image systemName="heart.fill" class="heart" />
Indicators
<Gauge>
Displays a value within a range.
<Gauge value="0.5">
<Text template="label">50%</Text>
<Text template="currentValueLabel">0.5</Text>
<Text template="minimumValueLabel">0</Text>
<Text template="maximumValueLabel">1</Text>
</Gauge>
<ProgressView>
Displays progress toward a target value.
<ProgressView />
<ProgressView value={0.5} />
<ProgressView value={0.5} total={2}>
<Text template={:label}>Completed Percentage</Text>
<Text template="currentValueLabel">25%</Text>
</ProgressView>
<ProgressView
counts-down
timerInterval:start={DateTime.utc_now()}
timerInterval:end={DateTime.utc_now() |> DateTime.add(5, :minute)}
/>
Lazy Grids
<LazyHGrid>
Grid that grows horizontally.
<LazyHGrid
rows={[
%{ size: %{ fixed: 100 } },
%{ size: :flexible },
%{ size: %{ adaptive: %{ minimum: 50 } } }
]}
>
<%= for i <- 1..50 do %>
<Text id={i |> Integer.to_string}><%= i %></Text>
<% end %>
</LazyHGrid>
<LazyVGrid>
Grid that grows vertically.
<LazyVGrid
columns={[
%{ size: %{ fixed: 100 } },
%{ size: :flexible },
%{ size: %{ adaptive: %{ minimum: 50 } } }
]}
>
<%= for i <- 1..50 do %>
<Text id={i |> Integer.to_string}><%= i %></Text>
<% end %>
</LazyVGrid>
Lazy Stacks
<LazyHStack>
Horizontal stack that creates Views lazily.
<ScrollView axes="horizontal">
<LazyHStack>
<%= for i <- 1..50 do %>
<Text id={i |> Integer.to_string} font="largeTitle"><%= i %></Text>
<% end %>
</LazyHStack>
</ScrollView>
<LazyVStack>
Vertical stack that creates Views lazily.
<ScrollView axes="vertical">
<LazyVStack>
<%= for i <- 1..50 do %>
<Text id={i |> Integer.to_string} font="largeTitle"><%= i %></Text>
<% end %>
</LazyVStack>
</ScrollView>
Links
<Link>
Opens a URL when tapped.
<Link destination="https://native.live">
Go to <Text class="bold">LiveView Native</Text>
</Link>
<ShareLink>
Opens a system share sheet when tapped.
<ShareLink
item="https://dockyard.com"
subject="Check out DockYard's website"
message="Here's a link to the DockYard homepage"
/>
<ShareLink
item="https://dockyard.com"
subject="Check out DockYard's website"
message="Here's a link to the DockYard homepage"
>
<SharePreview title="DockYard Homepage">
<Image template={:image} name="dockyard" />
<Image template={:icon} name="dockyard" />
</SharePreview>
</ShareLink>
<ShareLink
items='["https://dockyard.com", "https://news.ycombinator.com", "https://apple.com"]'
subject="Check out these websites"
message="Here are links to our favorite websites"
>
<SharePreview item="https://dockyard.com" title="DockYard">
<Image template={:image} name="dockyard" />
<Image template={:icon} name="dockyard" />
</SharePreview>
<SharePreview item="https://news.ycombinator.com" title="Hacker News">
<Image template={:image} name="hackernews" />
<Image template={:icon} name="hackernews" />
</SharePreview>
<SharePreview item="https://apple.com" title="Apple">
<Image template={:image} name="apple" />
<Image template={:icon} name="apple" />
</SharePreview>
</ShareLink>
<TextFieldLink>
A form element that requests text input on Apple Watch.
<TextFieldLink prompt="Favorite Color" value="color">
What's your favorite color?
</TextFieldLink>
Menus
<Menu>
Tappable element that expands to reveal a list of options.
<Menu>
<Text template={:label}>
Edit Actions
</Text>
<Group template={:content}>
<Button phx-click="arrange">Arrange</Button>
<Button phx-click="update">Update</Button>
<Button phx-click="remove">Remove</Button>
</Group>
</Menu>
Navigation
Pickers
<ColorPicker>
Presents a system color picker when tapped.
<ColorPicker selection={@favorite_color} phx-change="color-changed" supportsOpacity>
Favorite Color
</ColorPicker>
<DatePicker>
A control that lets the user pick a date.
<DatePicker selection="2023-03-14T15:19:26.535Z">
<Text>Pick a date</Text>
</DatePicker>
<MultiDatePicker>
A control that allows the user to pick multiple dates (not datetimes).
<MultiDatePicker selection={@dates} phx-change="dates-changed" start="2023-01-01" end="2023-02-01">
<Text>Pick as many dates as you like!</Text>
</MultiDatePicker>
<Picker>
A control that picks one of multiple values.
<Picker selection={@transport} phx-change="transport-changed">
<Text template={:label}>Transportation</Text>
<Group template={:content}>
<Label systemImage="car" tag="car">Car</Label>
<Label systemImage="bus" tag="bus">Bus</Label>
<Label systemImage="tram" tag="tram">Tram</Label>
</Group>
</Picker>
Presentation Containers
<HSplitView>
Container with resizable splits between elements.
<HSplitView>
<Rectangle fillColor="system-red" />
<Rectangle fillColor="system-blue" />
</HSplitView>
<NavigationLink>
A control users can tap to navigate to another live view.
<NavigationLink destination={"/products/#{@product.id}"}>
<Text>More Information</Text>
</NavigationLink>
<TabView>
Container that presents content on separate pages.
<TabView class="tab-view-style-page">
<Rectangle fillColor="system-red" />
<Rectangle fillColor="system-red" />
<Rectangle fillColor="system-red" />
</TabView>
<VSplitView>
Container with resizable splits between elements.
<VSplitView>
<Rectangle fillColor="system-red" />
<Rectangle fillColor="system-blue" />
</VSplitView>
Scroll Views
<ScrollView>
A view that lets it contents be scrolled if larger than the available space.
<ScrollView>
<VStack>
<%= for color <- @colors %>
<Rectangle id={color} fillColor={color} class="height:100" />
<% end %>
</VStack>
</ScrollView>
Separators
<Spacer>
A view that expands to provide space between other views.
<VStack>
<Text>First</Text>
<Spacer minLength="50" />
<Text>Second</Text>
</VStack>
Shapes
Shape
A view that displays the a shape.
Sizing
<ViewThatFits>
Chooses the first child that fits in the available space.
<ViewThatFits>
<Text>Long text content ... </Text>
<Image systemName="doc.text" />
</ViewThatFits>
Stacks
<HStack>
Container that lays out its children in a horizontal line.
<HStack>
<Text>Leading</Text>
<Spacer />
<Text>Trailing</Text>
</HStack>
<VStack>
Container that lays out its children in a vertical line.
<VStack>
<Text>Top</Text>
<Text>Bottom</Text>
</VStack>
<ZStack>
A container that lays out elements on top of each other, back to front.
<ZStack>
<Text>Back</Text>
<Text>Front</Text>
</ZStack>
Text Input and Output
<Label>
A title and icon pair.
<Label>
<Text template={:title}>John Doe</Text>
<Image template={:icon} systemName="person.crop.circle.fill" />
</Label>
<Label systemImage="person.crop.circle.fill">
<Text>John Doe</Text>
</Label>
<SecureField>
A form element for entering private text.
<SecureField prompt="Required" text="password">
Password
</SecureField>
<Text>
Displays text.
<Text>Hello</Text>
<Text verbatim="Hello"/>
<Text date="2023-03-14T15:19:00.000Z" dateStyle="date"/>
<Text date:start="2023-01-01" date:end="2024-01-01"/>
<Text markdown="Hello, *world*!" />
<Text value={15.99} format="currency" currencyCode="usd" />
<Text value="Doe John" format="name" nameStyle="short" />
"large-bold" do
font(.largeTitle)
bold()
end
<Text class="large-bold">
Hello, world!
</Text>
<Text>
<Image systemName="person.crop.circle.fill" /><Text value="Doe John" format="name" class="blue bold" />
<Text verbatim={"\n"} />
Check out this thing I made: <Link destination="mysite.com">mysite.com</Link>
</Text>
<TextEditor>
A multi-line, long-form text editor.
<TextEditor text="my_text" phx-focus="editor_focused" />
<TextField>
A form element for entering text.
<TextField text="first_name">
First Name
</TextField>
<TextField text="last_name">
<Text fontWeight="bold" font="caption">Last Name</Text>
</TextField>
"search-field" do
autocorrectDisabled(true)
textInputAutocapitalization(.words)
keyboardType(.webSearch)
submitLabel(.search)
end
<TextField
text="value"
class="search-field"
>
Enter Search Text
</TextField>
<VStack>
<TextField
text="amount"
format="currency"
currencyCode="usd"
class="decimal-pad"
>
Enter Amount
</TextField>
<TextField
text="bank_address"
axis="vertical"
>
Enter Bank Address
</TextField>
</VStack>
Toolbars
<ToolbarItem>
Toolbar element for placing items.
<ToolbarItem placement="destructiveAction">
<Button phx-click="delete">Delete</Button>
</ToolbarItem>
toolbar(id: "unique-toolbar-id", content: :my_toolbar_content)
<ToolbarItem id="delete">
...
</ToolbarItem>
<ToolbarItem id="delete" customizationBehavior="disabled">
...
</ToolbarItem>
<ToolbarItem id="delete" defaultVisibility="hidden" alwaysAvailable>
...
</ToolbarItem>
<ToolbarItemGroup>
Toolbar element for placing multiple items.
<ToolbarItemGroup placement="destructiveAction">
<Button phx-click="delete">Delete</Button>
<Button phx-click="destroy">Destroy</Button>
<Button phx-click="eradicate">Eradicate</Button>
</ToolbarItemGroup>
ToolbarTitleMenu
Toolbar element that opens a menu when the navigation title is tapped.
<ToolbarTitleMenu>
<Button phx-click="edit">Edit</Button>
<Button phx-click="save">Save</Button>
<Button phx-click="open">Open</Button>
</ToolbarItemMenu>
Value Inputs
<Slider>
A form element for selecting a value within a range.
<Slider value="progress" />
<Slider
value="progress"
lowerBound={-1}
upperBound={2}
/>
<Slider
value="progress"
lowerBound={0}
upperBound={10}
step={1}
/>
<Slider value="value">
<Text template="label">Percent Completed</Text>
<Text template="minimumValueLabel">0%</Text>
<Text template="maximumValueLabel">100%</Text>
</Slider>
<Stepper>
A form element for incrementing/decrementing a value in a range.
<Stepper value="attendees">
Attendees
</Stepper>
<Stepper
value="attendees"
lowerBound={0}
upperBound={16}
step={2}
>
Attendees
</Stepper>
<Toggle>
A form element that controls a boolean value.
<Toggle isOn={@lights_on} phx-change="toggled-lights">
Lights On
</Toggle>