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>

Opens a URL when tapped.

<Link destination="https://native.live">
    Go to <Text class="bold">LiveView Native</Text>
</Link>

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>

A form element that requests text input on Apple Watch.

<TextFieldLink prompt="Favorite Color" value="color">
    What's your favorite color?
</TextFieldLink>

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>

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>

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>