Common Patterns
Real-world examples showing how to use the library components together.
Dashboard Layout
A typical dashboard layout with sidebar and navbar:
<script setup lang="ts">
import {
DXDashboardSidebar,
DXDashboardNavbar,
DContainer
} from '@omnitend/dashboard-for-laravel'
import type { NavigationItem } from '@omnitend/dashboard-for-laravel'
const user = {
name: 'John Doe',
email: 'john@example.com'
}
const navigation: NavigationItem[] = [
{
label: 'Dashboard',
href: '/dashboard',
icon: 'bi:house-door'
},
{
label: 'Customers',
href: '/customers',
icon: 'bi:people'
},
{
label: 'Orders',
href: '/orders',
icon: 'bi:cart'
},
{
divider: true
},
{
label: 'Settings',
href: '/settings',
icon: 'bi:gear'
}
]
</script>
<template>
<div class="d-flex">
<DXDashboardSidebar :navigation="navigation" :user="user" />
<div class="flex-grow-1">
<DXDashboardNavbar :user="user" />
<DContainer fluid class="p-4">
<!-- Page content -->
<slot />
</DContainer>
</div>
</div>
</template>
Data Table with Pagination
Display paginated data with a table:
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { DXTable, DCard, DButton } from '@omnitend/dashboard-for-laravel'
import { api } from '@omnitend/dashboard-for-laravel'
const customers = ref([])
const pagination = ref(null)
const loading = ref(false)
const fields = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'business_name', label: 'Business Name', sortable: true },
{ key: 'contact_name', label: 'Contact' },
{ key: 'email', label: 'Email' },
{ key: 'actions', label: 'Actions' }
]
const loadCustomers = async (page = 1) => {
loading.value = true
try {
const response = await api.get(`/api/customers?page=${page}`)
customers.value = response.data.data
pagination.value = response.data.meta
} finally {
loading.value = false
}
}
onMounted(() => loadCustomers())
</script>
<template>
<DCard>
<template #header>
<div class="d-flex justify-content-between align-items-centre">
<h3>Customers</h3>
<DButton variant="primary" @click="$router.push('/customers/create')">
Add Customer
</DButton>
</div>
</template>
<DXTable
:items="customers"
:fields="fields"
:pagination="pagination"
:loading="loading"
@page-changed="loadCustomers"
>
<template #cell(actions)="{ item }">
<DButton
variant="link"
size="sm"
@click="$router.push(`/customers/${item.id}/edit`)"
>
Edit
</DButton>
</template>
</DXTable>
</DCard>
</template>
Form with Validation
Create a form with validation and error handling:
<script setup lang="ts">
import { useRouter } from 'vue-router'
import {
useForm,
useToast,
DCard,
DXBasicForm
} from '@omnitend/dashboard-for-laravel'
import type { FieldDefinition } from '@omnitend/dashboard-for-laravel'
const router = useRouter()
const toast = useToast()
const form = useForm({
business_name: '',
contact_name: '',
email: '',
phone: '',
address: '',
postcode: '',
country: 'UK'
})
const fields: FieldDefinition[] = [
{
key: 'business_name',
label: 'Business Name',
type: 'text',
required: true,
placeholder: 'Enter business name'
},
{
key: 'contact_name',
label: 'Contact Name',
type: 'text',
required: true,
placeholder: 'Enter contact name'
},
{
key: 'email',
label: 'Email Address',
type: 'email',
required: true,
placeholder: 'contact@example.com'
},
{
key: 'phone',
label: 'Phone Number',
type: 'tel',
placeholder: '+44 20 1234 5678'
},
{
key: 'address',
label: 'Address',
type: 'textarea',
placeholder: 'Enter full address'
},
{
key: 'postcode',
label: 'Postcode',
type: 'text',
placeholder: 'SW1A 1AA'
},
{
key: 'country',
label: 'Country',
type: 'select',
required: true,
options: [
{ value: 'UK', text: 'United Kingdom' },
{ value: 'US', text: 'United States' },
{ value: 'CA', text: 'Canada' }
]
}
]
const handleSubmit = async () => {
await form.post('/api/customers', {
onSuccess: () => {
toast.success('Customer created successfully')
router.push('/customers')
},
onError: () => {
toast.error('Please fix the validation errors')
}
})
}
</script>
<template>
<DCard>
<template #header>
<h3>Create Customer</h3>
</template>
<DXBasicForm
:fields="fields"
:form="form"
submit-text="Create Customer"
@submit="handleSubmit"
/>
</DCard>
</template>
Collapsible Sections
Use collapse for expandable content:
<script setup lang="ts">
import { ref } from 'vue'
import { DCard, DButton, DCollapse } from '@omnitend/dashboard-for-laravel'
const detailsVisible = ref(false)
const settingsVisible = ref(false)
</script>
<template>
<DCard>
<div class="d-flex justify-content-between align-items-centre mb-3">
<h4>Customer Details</h4>
<DButton
variant="link"
@click="detailsVisible = !detailsVisible"
>
{{ detailsVisible ? 'Hide' : 'Show' }} Details
</DButton>
</div>
<DCollapse v-model="detailsVisible">
<div class="card card-body">
<p><strong>Business:</strong> Acme Ltd</p>
<p><strong>Contact:</strong> John Smith</p>
<p><strong>Email:</strong> john@acme.com</p>
</div>
</DCollapse>
<div class="d-flex justify-content-between align-items-centre mb-3 mt-4">
<h4>Settings</h4>
<DButton
variant="link"
@click="settingsVisible = !settingsVisible"
>
{{ settingsVisible ? 'Hide' : 'Show' }} Settings
</DButton>
</div>
<DCollapse v-model="settingsVisible">
<div class="card card-body">
<p>Settings content here...</p>
</div>
</DCollapse>
</DCard>
</template>
Modal Dialog
Show a modal for confirmations:
<script setup lang="ts">
import { ref } from 'vue'
import { DButton, DModal } from '@omnitend/dashboard-for-laravel'
const showDeleteModal = ref(false)
const handleDelete = async () => {
// Perform delete action
console.log('Deleting...')
showDeleteModal.value = false
}
</script>
<template>
<div>
<DButton variant="danger" @click="showDeleteModal = true">
Delete Customer
</DButton>
<DModal v-model="showDeleteModal" title="Confirm Delete">
<p>Are you sure you want to delete this customer?</p>
<p class="text-muted">This action cannot be undone.</p>
<template #footer>
<DButton variant="secondary" @click="showDeleteModal = false">
Cancel
</DButton>
<DButton variant="danger" @click="handleDelete">
Delete
</DButton>
</template>
</DModal>
</div>
</template>
Toast Notifications
Show feedback to users with toasts:
<script setup lang="ts">
import { useToast, DButton, DCard } from '@omnitend/dashboard-for-laravel'
const toast = useToast()
const showSuccess = () => {
toast.success('Operation completed successfully!')
}
const showError = () => {
toast.error('Something went wrong. Please try again.')
}
const showInfo = () => {
toast.info('This is an informational message.')
}
const showWarning = () => {
toast.warning('Please review this warning.')
}
</script>
<template>
<DCard>
<template #header>
<h3>Toast Examples</h3>
</template>
<div class="d-flex gap-2">
<DButton variant="success" @click="showSuccess">
Success Toast
</DButton>
<DButton variant="danger" @click="showError">
Error Toast
</DButton>
<DButton variant="info" @click="showInfo">
Info Toast
</DButton>
<DButton variant="warning" @click="showWarning">
Warning Toast
</DButton>
</div>
</DCard>
</template>
Search and Filter
Implement search and filtering:
<script setup lang="ts">
import { ref, computed } from 'vue'
import {
DCard,
DFormInput,
DFormSelect,
DTable
} from '@omnitend/dashboard-for-laravel'
const searchQuery = ref('')
const statusFilter = ref('all')
const customers = ref([
{ id: 1, name: 'Acme Ltd', status: 'active' },
{ id: 2, name: 'Tech Corp', status: 'inactive' },
{ id: 3, name: 'Global Inc', status: 'active' }
])
const filteredCustomers = computed(() => {
return customers.value.filter(customer => {
const matchesSearch = customer.name
.toLowerCase()
.includes(searchQuery.value.toLowerCase())
const matchesStatus =
statusFilter.value === 'all' ||
customer.status === statusFilter.value
return matchesSearch && matchesStatus
})
})
const fields = [
{ key: 'id', label: 'ID' },
{ key: 'name', label: 'Name' },
{ key: 'status', label: 'Status' }
]
</script>
<template>
<DCard>
<template #header>
<h3>Customers</h3>
</template>
<div class="row mb-3">
<div class="col-md-6">
<DFormInput
v-model="searchQuery"
placeholder="Search customers..."
/>
</div>
<div class="col-md-6">
<DFormSelect v-model="statusFilter">
<option value="all">All Status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</DFormSelect>
</div>
</div>
<DTable :items="filteredCustomers" :fields="fields" />
</DCard>
</template>
Next Steps
- Component Reference - Explore all components
- Form System - Learn more about forms
- Theming - Customise the appearance