Item
An item is a flexible list entry used to display structured content such as a media element, text, and actions. It is composed of several sub-components that each handle a specific area of the item.
Props
is-control?: boolean
Renders the item as a label so that clicking anywhere in the row toggles the single form control (toggle, checkbox or radio) it contains.
Slots
default
The content of the item, typically composed of item sub-components.
Examples
Clickable
Wrap an item in a clickable pane to turn it into an interactive list entry. The whole row highlights on hover.
<template>
<div style="display: flex; flex-flow: column; gap: 9px; width: min(100%, 420px)">
<FluxClickablePane
v-for="project in projects"
:key="project.name"
type="button">
<FluxItem>
<FluxItemMedia
is-center
:size="40">
<FluxBoxedIcon
:color="project.color"
:name="project.icon"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ project.name }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ project.description }}</span>
</FluxItemContent>
<FluxItemMedia is-center>
<FluxIcon
name="angle-right"
style="opacity: .4"/>
</FluxItemMedia>
</FluxItem>
</FluxClickablePane>
</div>
</template>
<script
setup
lang="ts">
import type { FluxColor, FluxIconName } from '@flux-ui/types';
import { FluxBoxedIcon, FluxClickablePane, FluxIcon, FluxItem, FluxItemContent, FluxItemMedia } from '@flux-ui/components';
const projects: { name: string; description: string; icon: FluxIconName; color: FluxColor }[] = [
{name: 'Aurora', description: 'Design system', icon: 'palette', color: 'primary'},
{name: 'Nebula', description: 'Marketing site', icon: 'rocket', color: 'info'},
{name: 'Orbit', description: 'Analytics dashboard', icon: 'chart-line', color: 'success'}
];
</script>Complete
An item composed of media, content and actions stacked together.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="member in members"
:key="member.name">
<FluxItemMedia
is-center
:size="40">
<FluxAvatar
:alt="member.name"
fallback-icon="user"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ member.name }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ member.role }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxAction
icon="pen"
aria-label="Edit"/>
<FluxAction
is-destructive
icon="trash"
aria-label="Remove"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { FluxAction, FluxAvatar, FluxItem, FluxItemActions, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane } from '@flux-ui/components';
const members = [
{name: 'Bas Milius', role: 'Engineer'},
{name: 'Jane Doe', role: 'Designer'},
{name: 'John Doe', role: 'Product manager'}
];
</script>Notifications
A notification feed with a leading icon, message, timestamp and a dismiss action.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="notification in notifications"
:key="notification.title">
<FluxItemMedia
is-center
:size="40">
<FluxBoxedIcon
:color="notification.color"
:name="notification.icon"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ notification.title }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ notification.time }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxAction
icon="xmark"
aria-label="Dismiss"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import type { FluxColor, FluxIconName } from '@flux-ui/types';
import { FluxAction, FluxBoxedIcon, FluxItem, FluxItemActions, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane } from '@flux-ui/components';
const notifications: { title: string; time: string; icon: FluxIconName; color: FluxColor }[] = [
{title: 'Jane Doe started following you', time: '2 minutes ago', icon: 'user-plus', color: 'info'},
{title: 'John Doe liked your post', time: '1 hour ago', icon: 'heart', color: 'danger'},
{title: 'New comment on Release notes', time: '3 hours ago', icon: 'message', color: 'primary'}
];
</script>Settings
A settings list where each row pairs a description with a switch.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="setting in items"
:key="setting.key">
<FluxItemContent>
<strong>{{ setting.label }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ setting.description }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxToggle v-model="settings[setting.key]"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { reactive } from 'vue';
import { FluxItem, FluxItemActions, FluxItemContent, FluxItemStack, FluxPane, FluxToggle } from '@flux-ui/components';
const settings = reactive<Record<string, boolean>>({
push: true,
email: false,
twoFactor: true
});
const items = [
{key: 'push', label: 'Push notifications', description: 'Receive alerts on your devices.'},
{key: 'email', label: 'Email digest', description: 'A weekly summary in your inbox.'},
{key: 'twoFactor', label: 'Two-factor authentication', description: 'Add an extra layer of security.'}
];
</script>Control
With is-control the whole row becomes the label for its form control. Click anywhere to toggle.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="option in options"
:key="option.key"
is-control>
<FluxItemContent is-center>
<strong>{{ option.label }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ option.description }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxToggle v-model="enabled[option.key]"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { reactive } from 'vue';
import { FluxItem, FluxItemActions, FluxItemContent, FluxItemStack, FluxPane, FluxToggle } from '@flux-ui/components';
const enabled = reactive<Record<string, boolean>>({
marketing: true,
product: false,
security: true
});
const options = [
{key: 'marketing', label: 'Marketing emails', description: 'News, offers and product announcements.'},
{key: 'product', label: 'Product updates', description: 'Release notes and changelogs.'},
{key: 'security', label: 'Security alerts', description: 'Important notices about your account.'}
];
</script>Selectable
A multi-select list where the whole row toggles the checkbox, thanks to is-control.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="member in members"
:key="member.key"
is-control>
<FluxItemMedia is-center>
<FluxFormCheckbox v-model="selected[member.key]"/>
</FluxItemMedia>
<FluxItemMedia
is-center
:size="40">
<FluxAvatar
:alt="member.name"
fallback-icon="user"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ member.name }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ member.email }}</span>
</FluxItemContent>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { reactive } from 'vue';
import { FluxAvatar, FluxFormCheckbox, FluxItem, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane } from '@flux-ui/components';
const selected = reactive<Record<string, boolean>>({
bas: true,
jane: false,
john: true
});
const members = [
{key: 'bas', name: 'Bas Milius', email: 'bas@example.com'},
{key: 'jane', name: 'Jane Doe', email: 'jane@example.com'},
{key: 'john', name: 'John Doe', email: 'john@example.com'}
];
</script>Integrations
Connected services with a status badge and a toggle to connect or disconnect.
<template>
<FluxPane style="width: min(100%, 520px)">
<FluxItemStack>
<FluxItem
v-for="app in apps"
:key="app.key"
is-control>
<FluxItemMedia
is-center
:size="40">
<FluxBoxedIcon
:color="app.color"
:name="app.icon"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ app.name }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ app.description }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxBadge
:color="connected[app.key] ? 'success' : 'gray'"
:label="connected[app.key] ? 'Connected' : 'Disconnected'"/>
<FluxToggle v-model="connected[app.key]"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import type { FluxColor, FluxIconName } from '@flux-ui/types';
import { reactive } from 'vue';
import { FluxBadge, FluxBoxedIcon, FluxItem, FluxItemActions, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane, FluxToggle } from '@flux-ui/components';
const connected = reactive<Record<string, boolean>>({
github: true,
slack: true,
drive: false
});
const apps: { key: string; name: string; description: string; icon: FluxIconName; color: FluxColor }[] = [
{key: 'github', name: 'GitHub', description: 'Sync issues and pull requests.', icon: 'code-branch', color: 'gray'},
{key: 'slack', name: 'Slack', description: 'Send updates to your channels.', icon: 'message', color: 'primary'},
{key: 'drive', name: 'Cloud Storage', description: 'Attach files from the cloud.', icon: 'cloud', color: 'info'}
];
</script>Transactions
A transaction list with a directional icon and a trailing amount.
<template>
<FluxPane style="width: min(100%, 480px)">
<FluxItemStack>
<FluxItem
v-for="transaction in transactions"
:key="transaction.merchant">
<FluxItemMedia
is-center
:size="40">
<FluxBoxedIcon
:color="transaction.isIncome ? 'success' : 'gray'"
:name="transaction.isIncome ? 'arrow-trend-up' : 'arrow-trend-down'"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ transaction.merchant }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ transaction.date }}</span>
</FluxItemContent>
<FluxItemContent
is-center
style="flex-grow: 0; text-align: right">
<strong :style="{color: transaction.isIncome ? 'var(--success-600)' : undefined}">{{ transaction.amount }}</strong>
</FluxItemContent>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { FluxBoxedIcon, FluxItem, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane } from '@flux-ui/components';
const transactions = [
{merchant: 'Acme Inc.', date: 'June 14, 2026', amount: '+€2,400.00', isIncome: true},
{merchant: 'Coffee Roasters', date: 'June 13, 2026', amount: '-€4.80', isIncome: false},
{merchant: 'Cloud Hosting', date: 'June 12, 2026', amount: '-€19.99', isIncome: false}
];
</script>Downloads
Active downloads with an inline progress bar and a cancel action.
<template>
<FluxPane style="width: min(100%, 520px)">
<FluxItemStack>
<FluxItem
v-for="download in downloads"
:key="download.name">
<FluxItemMedia
is-center
:size="40">
<FluxBoxedIcon
color="primary"
name="file-lines"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ download.name }}</strong>
<FluxProgressBar
:value="download.progress"
:max="100"/>
<span style="font-size: .875rem; opacity: .6">{{ download.progress }}% of {{ download.size }}</span>
</FluxItemContent>
<FluxItemActions is-center>
<FluxAction
icon="xmark"
aria-label="Cancel"/>
</FluxItemActions>
</FluxItem>
</FluxItemStack>
</FluxPane>
</template>
<script
setup
lang="ts">
import { FluxAction, FluxBoxedIcon, FluxItem, FluxItemActions, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane, FluxProgressBar } from '@flux-ui/components';
const downloads = [
{name: 'annual-report.pdf', size: '8.2 MB', progress: 72},
{name: 'design-assets.zip', size: '254 MB', progress: 35}
];
</script>Snippet
<template>
<Preview>
<FluxPane style="width: min(100%, 420px)">
<FluxItemStack>
<FluxItem
v-for="person in people"
:key="person.name">
<FluxItemMedia
is-center
:size="40">
<FluxAvatar
:alt="person.name"
:fallback-icon="person.avatar ? undefined : 'user'"
:src="person.avatar"
:size="40"/>
</FluxItemMedia>
<FluxItemContent is-center>
<strong>{{ person.name }}</strong>
<span style="font-size: .875rem; opacity: .6">{{ person.role }}</span>
</FluxItemContent>
</FluxItem>
</FluxItemStack>
</FluxPane>
</Preview>
</template>
<script
setup
lang="ts">
import { FluxAvatar, FluxItem, FluxItemContent, FluxItemMedia, FluxItemStack, FluxPane } from '@flux-ui/components';
const people = [
{name: 'Bas Milius', role: 'Engineer', avatar: 'https://avatars.githubusercontent.com/u/978257?v=4'},
{name: 'Jane Doe', role: 'Designer', avatar: null},
{name: 'John Doe', role: 'Product manager', avatar: null}
];
</script>