Appearance
ContentLayout Component
A flexible layout component for creating consistent page headers with breadcrumb-style titles, action buttons, and body content areas. Perfect for admin panels, dashboards, and content management interfaces.
Table of Contents
Basic Usage
Simple Layout
vue
<template>
<ContentLayout
:title="[{ name: 'Dashboard' }]"
>
<template #body>
<p>Your content goes here</p>
</template>
</ContentLayout>
</template>
<script setup>
import { ContentLayout } from 'dolphin-components';
</script>With Action Button
vue
<template>
<ContentLayout
:title="[{ name: 'Users' }]"
:actions="[
{ title: 'Add User', emit: 'onCreate', class: 'btn btn-primary' }
]"
@onCreate="handleCreate"
>
<template #body>
<p>User list content</p>
</template>
</ContentLayout>
</template>
<script setup>
import { ContentLayout } from 'dolphin-components';
const handleCreate = () => {
console.log('Create new user');
};
</script>Props
title
Type: ContentTitle[]
Default: []
Required: No
An array of title objects that creates a breadcrumb-style navigation header.
ContentTitle Interface:
typescript
interface ContentTitle {
name: string; // Display text
link?: string; // Optional route link
count?: number; // Optional item count badge
}Examples:
vue
<!-- Single title -->
<ContentLayout :title="[{ name: 'Dashboard' }]" />
<!-- Breadcrumb navigation -->
<ContentLayout
:title="[
{ name: 'Home', link: '/' },
{ name: 'Users', link: '/users' },
{ name: 'Edit User' }
]"
/>
<!-- With item count -->
<ContentLayout
:title="[
{ name: 'Products', count: 150 }
]"
/>actions
Type: ContentAction[]
Default: []
Required: No
An array of action button configurations displayed in the header.
ContentAction Interface:
typescript
interface ContentAction {
title: string; // Button text
emit: string; // Event name to emit on click
class?: string; // Custom CSS classes (default: 'btn btn-primary')
}Examples:
vue
<!-- Single action -->
<ContentLayout
:actions="[
{ title: 'Create', emit: 'onCreate' }
]"
@onCreate="handleCreate"
/>
<!-- Multiple actions with custom classes -->
<ContentLayout
:actions="[
{ title: 'Save', emit: 'onSave', class: 'btn btn-primary' },
{ title: 'Cancel', emit: 'onCancel', class: 'btn btn-outline-secondary' },
{ title: 'Delete', emit: 'onDelete', class: 'btn btn-danger' }
]"
@onSave="handleSave"
@onCancel="handleCancel"
@onDelete="handleDelete"
/>bodyClass
Type: string
Default: ""
Required: No
Custom CSS classes to apply to the body content area.
Examples:
vue
<!-- Add padding -->
<ContentLayout body-class="p-6">
<template #body>
<p>Padded content</p>
</template>
</ContentLayout>
<!-- Custom background -->
<ContentLayout body-class="bg-gray-50 rounded-lg">
<template #body>
<p>Content with background</p>
</template>
</ContentLayout>
<!-- Multiple classes -->
<ContentLayout body-class="p-8 bg-white shadow-md rounded-xl">
<template #body>
<p>Styled content</p>
</template>
</ContentLayout>titleClass
Type: string
Default: ""
Required: No
Custom CSS classes to apply to the title/header area.
Examples:
vue
<!-- Custom background -->
<ContentLayout title-class="bg-blue-50 border-b-2 border-blue-200">
<template #body>
<p>Content</p>
</template>
</ContentLayout>
<!-- Custom padding -->
<ContentLayout title-class="py-6 px-8">
<template #body>
<p>Content</p>
</template>
</ContentLayout>disableMinHeight
Type: boolean
Default: false
Required: No
Disables the default minimum height constraint on the body content area. Useful for pages that need to be compact or have dynamic heights.
Examples:
vue
<!-- Default: Has minimum height -->
<ContentLayout>
<template #body>
<p>Content with minimum height</p>
</template>
</ContentLayout>
<!-- Disabled: No minimum height -->
<ContentLayout :disable-min-height="true">
<template #body>
<p>Compact content without minimum height</p>
</template>
</ContentLayout>Slots
body (Default Slot)
The main content area of the layout.
vue
<ContentLayout :title="[{ name: 'Page Title' }]">
<template #body>
<!-- Your main content here -->
<div>
<h2>Section Title</h2>
<p>Content goes here</p>
</div>
</template>
</ContentLayout>action-before
Insert custom elements before the action buttons in the header.
vue
<ContentLayout
:title="[{ name: 'Products' }]"
:actions="[{ title: 'Add Product', emit: 'onCreate' }]"
>
<template #action-before>
<button class="btn btn-outline-secondary">
<Icons name="Filter" />
Filter
</button>
</template>
<template #body>
<p>Product list</p>
</template>
</ContentLayout>action-after
Insert custom elements after the action buttons in the header.
vue
<ContentLayout
:title="[{ name: 'Settings' }]"
:actions="[{ title: 'Save', emit: 'onSave' }]"
>
<template #action-after>
<button class="btn btn-outline-danger">
<Icons name="Trash" />
</button>
</template>
<template #body>
<p>Settings content</p>
</template>
</ContentLayout>Styling
CSS Classes
The component uses the following CSS classes that you can customize:
css
/* Main container */
.content-div {
/* Wrapper for entire component */
}
/* Title/Header section */
.content-title-div {
/* Header container */
/* Can be customized via titleClass prop */
}
.content-title {
/* Breadcrumb/title container */
}
/* Action buttons section */
.content-action {
/* Action buttons container */
}
/* Body content section */
.content-body {
/* Main content container */
/* Can be customized via bodyClass prop */
}
.content-body-min-height {
/* Minimum height class (can be disabled) */
}Custom Styling Examples
vue
<!-- Custom header styling -->
<ContentLayout
title-class="bg-gradient-to-r from-blue-500 to-purple-600 text-white py-6"
:title="[{ name: 'Dashboard' }]"
>
<template #body>
<p>Content</p>
</template>
</ContentLayout>
<!-- Custom body styling -->
<ContentLayout
:title="[{ name: 'Products' }]"
body-class="bg-gray-50 p-8 rounded-xl shadow-inner"
>
<template #body>
<p>Content</p>
</template>
</ContentLayout>
<!-- Combined custom styling -->
<ContentLayout
title-class="border-b-4 border-blue-500 pb-4"
body-class="p-6 bg-white shadow-lg rounded-lg mt-4"
:title="[{ name: 'Settings' }]"
>
<template #body>
<p>Content</p>
</template>
</ContentLayout>Best Practices
1. Use Breadcrumb Navigation for Deep Pages
vue
<!-- Good: Clear navigation hierarchy -->
<ContentLayout
:title="[
{ name: 'Dashboard', link: '/' },
{ name: 'Products', link: '/products' },
{ name: 'Category', link: '/products/category' },
{ name: 'Edit Product' }
]"
>
<template #body>...</template>
</ContentLayout>2. Show Item Counts for List Pages
vue
<!-- Good: Shows total count -->
<ContentLayout
:title="[{ name: 'Users', count: totalUsers }]"
:actions="[{ title: 'Add User', emit: 'onCreate' }]"
>
<template #body>...</template>
</ContentLayout>3. Group Related Actions
vue
<!-- Good: Primary action on the right -->
<ContentLayout
:actions="[
{ title: 'Cancel', emit: 'onCancel', class: 'btn btn-outline-secondary' },
{ title: 'Save', emit: 'onSave', class: 'btn btn-primary' }
]"
>
<template #body>...</template>
</ContentLayout>4. Use Consistent Action Button Classes
vue
<!-- Good: Semantic button classes -->
<ContentLayout
:actions="[
{ title: 'Delete', emit: 'onDelete', class: 'btn btn-danger' },
{ title: 'Edit', emit: 'onEdit', class: 'btn btn-primary' }
]"
>
<template #body>...</template>
</ContentLayout>5. Disable Minimum Height for Compact Sections
vue
<!-- Good: Compact layout for small sections -->
<ContentLayout
:title="[{ name: 'Quick Stats' }]"
:disable-min-height="true"
>
<template #body>
<div class="flex gap-4">
<!-- Compact content -->
</div>
</template>
</ContentLayout>6. Use Slots for Complex Action Areas
vue
<!-- Good: Custom actions with search -->
<ContentLayout :title="[{ name: 'Products' }]">
<template #action-before>
<input type="text" placeholder="Search..." class="input-text" />
<button class="btn btn-outline-secondary">Filter</button>
</template>
<template #action-after>
<button class="btn btn-primary">Add Product</button>
</template>
<template #body>...</template>
</ContentLayout>TypeScript Support
The component is fully typed with TypeScript interfaces:
typescript
interface ContentTitle {
name: string;
link?: string;
count?: number;
}
interface ContentAction {
title: string;
emit: string;
class?: string;
}
interface ContentProps {
title?: ContentTitle[];
actions?: ContentAction[];
bodyClass?: string;
titleClass?: string;
disableMinHeight?: boolean;
}Usage with TypeScript
vue
<script setup lang="ts">
import { ref } from 'vue';
import { ContentLayout, type ContentTitle, type ContentAction } from 'dolphin-components';
const pageTitle = ref<ContentTitle[]>([
{ name: 'Dashboard', link: '/' },
{ name: 'Users', count: 150 }
]);
const pageActions = ref<ContentAction[]>([
{ title: 'Add User', emit: 'onCreate', class: 'btn btn-primary' }
]);
const handleCreate = (): void => {
console.log('Creating new user');
};
</script>
<template>
<ContentLayout
:title="pageTitle"
:actions="pageActions"
@onCreate="handleCreate"
>
<template #body>
<p>Content</p>
</template>
</ContentLayout>
</template>Troubleshooting
Title/Breadcrumbs Not Showing
Make sure you're passing the title prop correctly:
vue
<!-- ❌ Wrong -->
<ContentLayout title="Dashboard" />
<!-- ✅ Correct -->
<ContentLayout :title="[{ name: 'Dashboard' }]" />Actions Not Triggering
Ensure you're listening to the correct event:
vue
<!-- ❌ Wrong: emit name doesn't match event listener -->
<ContentLayout
:actions="[{ title: 'Save', emit: 'onSave' }]"
@save="handleSave"
/>
<!-- ✅ Correct: emit matches event listener -->
<ContentLayout
:actions="[{ title: 'Save', emit: 'onSave' }]"
@onSave="handleSave"
/>RouterLink Not Working
Make sure Vue Router is installed and configured:
javascript
// main.js
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
const router = createRouter({
history: createWebHistory(),
routes: [
// your routes
]
});
const app = createApp(App);
app.use(router);
app.mount('#app');Minimum Height Issue
If you want the body to be more compact:
vue
<!-- Disable minimum height -->
<ContentLayout :disable-min-height="true">
<template #body>
<p>Compact content</p>
</template>
</ContentLayout>