Tailwind CSS Container Explanation
December 15, 2024 · AI Conversations
– **`container`**: Centers the content and applies a fixed maximum width that adjusts based on the screen size.
– **`p-4`**: Adds padding of `1
### Code Example
<div class="container p-4 sm:p-0 flex justify-center items-center min-h-screen">
<form class="w-full sm:w-1/2 bg-white shadow-md rounded-lg p-6">
<h2 class="text-2xl font-bold mb-4 text-center">Register</h2>
<div class="mb-4">
<label for="name" class="block text-gray-700 font-medium mb-2">Name</label>
<input type="text" id="name" name="name" placeholder="Enter your name"
class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="email" class="block text-gray-700 font-medium mb-2">Email</label>
<input type="email" id="email" name="email" placeholder="Enter your email"
class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<div class="mb-4">
<label for="password" class="block text-gray-700 font-medium mb-2">Password</label>
<input type="password" id="password" name="password" placeholder="Enter your password"
class="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<button type="submit"
class="w-full bg-blue-500 text-white font-medium py-3 rounded-lg hover:bg-blue-600 transition">
Register
</button>
</form>
</div>
### Explanation
1. **Outer “**:
– `container`: Centers the content and adds responsiveness.
– `flex justify-center items-center`: Centers the form both horizontally and vertically.
– `min-h-screen`: Ensures the container takes up the full height of the viewport.
2. **`form` element**:
– `w-full sm:w-1/2`: Full width on mobile (`w-full`), 50% width on larger screens (`sm:w-1/2`).
– `bg-white shadow-md rounded-lg p-6`: Styles the form with a background color, shadow, rounded corners, and padding.
3. **Responsive Classes**:
– `sm:` prefix applies styles starting at the `sm` breakpoint (640px).
– This makes the form responsive and mobile-friendly.
4. **Form Fields**:
– `w-full`: Ensures the inputs span the entire width of the form.
– `focus:outline-none focus:ring-2 focus:ring-blue-500`: Adds a blue focus ring for accessibility and better UX.
### Result
– **On mobile**: The form is full width.
– **On desktop**: The form is centered and takes up 50% of the container width.
You can adjust colors, padding, or additional styling as needed!
<script>
import { ref, onMounted } from 'vue';
import { Link } from '@inertiajs/vue3';
import ApplicationLogo from '@/Components/ApplicationLogo.vue';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';
const isMenuOpen=ref(false);
function toggleMenu() {
isMenuOpen.value = !isMenuOpen.value;
}
</script>
SYT
Open main menu
Post
{{ $t('login') }}
{{ $t('register') }}
we have layout in vue now I want to pass "flex justify-center items-center min-h-screen" under div class from page where i included this layout
### Update Your Layout Component
Add a `props` definition for the dynamic class and use it in the `class` binding of your “.
<script setup>
import { ref, onMounted } from 'vue';
import { Link } from '@inertiajs/vue3';
import ApplicationLogo from '@/Components/ApplicationLogo.vue';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';
const isMenuOpen = ref(false);
function toggleMenu() {
isMenuOpen.value = !isMenuOpen.value;
}
// Define props
defineProps({
contentClass: {
type: String,
default: 'flex justify-center items-center min-h-screen', // Default class
},
});
</script>
<template>
<nav class="border-b border-indigo-200 bg-grey-50">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<Link href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center text-2xl font-semibold whitespace-nowrap text-menuitem">SYT</span>
</Link>
<button @click="toggleMenu" data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-default" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
</svg>
</button>
<div :class="{'hidden': !isMenuOpen, 'w-full': true, 'md:block': true, 'md:w-auto': true}" id="navbar-default">
<ul class="flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0">
<Link :href="route('front.home.index')" class="block py-2 px-3 text-menuitemrounded md:bg-transparent md:p-0 text-menuitem hover:text-indigo-200">Post</Link>
<li>
<Link :href="route('login')" class="block py-2 px-3 text-menuitemrounded md:bg-transparent md:p-0 text-menuitem hover:text-indigo-200" aria-current="page">{{ $t('login') }}</Link>
</li>
<li>
<Link :href="route('register')" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 hover:text-indigo-200 md:p-0 dark:text-menuitem md:dark:hover:text-blue-500 md:dark:hover:bg-transparent text-menuitem">{{ $t('register') }}</Link>
</li>
<li>
<LanguageSwitcher></LanguageSwitcher>
</li>
</ul>
</div>
</div>
</nav>
<!-- Dynamic Content Class -->
<div :class="contentClass">
<slot />
</div>
</template>
### Explanation
1. **Define Props**:
– The `contentClass` prop is added to allow passing dynamic class names.
– Default value for `contentClass` is set to `flex justify-center items-center min-h-screen`.
2. **Dynamic Class Binding**:
– The `contentClass` prop is bound to the `class` attribute of the “.
### Using the Layout Component
Now, when you include this layout in a page, you can pass a custom class as follows:
<script setup>
// Example of a page using the layout
</script>
<template>
<Layout content-class="flex flex-col items-center justify-start">
<h1 class="text-4xl font-bold">Welcome to the Page</h1>
<p class="text-gray-600">This is some content inside the layout.</p>
</Layout>
</template>
### Result
– The layout will apply the class `flex flex-col items-center justify-start` to the container “.
– If no `content-class` is passed, the default `flex justify-center items-center min-h-screen` will be used.
This makes your layout reusable and flexible!
Here’s how you can update your layout:
### Updated Layout Component
<script setup>
import { ref, onMounted } from 'vue';
import { Link } from '@inertiajs/vue3';
import ApplicationLogo from '@/Components/ApplicationLogo.vue';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';
const isMenuOpen = ref(false);
function toggleMenu() {
isMenuOpen.value = !isMenuOpen.value;
}
// Define props
defineProps({
contentClass: {
type: String,
default: 'flex justify-center items-center min-h-screen', // Default dynamic classes
},
});
</script>
<template>
<nav class="border-b border-indigo-200 bg-grey-50">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<Link href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<span class="self-center text-2xl font-semibold whitespace-nowrap text-menuitem">SYT</span>
</Link>
<button @click="toggleMenu" data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-default" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
</svg>
</button>
<div :class="{'hidden': !isMenuOpen, 'w-full': true, 'md:block': true, 'md:w-auto': true}" id="navbar-default">
<ul class="flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0">
<Link :href="route('front.home.index')" class="block py-2 px-3 text-menuitemrounded md:bg-transparent md:p-0 text-menuitem hover:text-indigo-200">Post</Link>
<li>
<Link :href="route('login')" class="block py-2 px-3 text-menuitemrounded md:bg-transparent md:p-0 text-menuitem hover:text-indigo-200" aria-current="page">{{ $t('login') }}</Link>
</li>
<li>
<Link :href="route('register')" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 hover:text-indigo-200 md:p-0 dark:text-menuitem md:dark:hover:text-blue-500 md:dark:hover:bg-transparent text-menuitem">{{ $t('register') }}</Link>
</li>
<li>
<LanguageSwitcher></LanguageSwitcher>
</li>
</ul>
</div>
</div>
</nav>
<!-- Dynamic Content Class with Static "container" Class -->
<div :class="['container', contentClass]">
<slot />
</div>
</template>
### Explanation
1. **Static and Dynamic Classes**:
– The `container` class is always present.
– The `contentClass` prop dynamically appends additional classes.
:class="['container', contentClass]"
– This approach ensures that `container` is never overridden, and any additional classes passed via `contentClass` are appended.
2. **Props**:
– The `contentClass` prop allows you to pass extra classes, with a default of `flex justify-center items-center min-h-screen`.
### Using the Layout Component
#### Example 1: Default Behavior
If no `content-class` is passed, the `container` class is combined with the default:
<Layout>
<h1 class="text-4xl font-bold">Welcome to the Page</h1>
</Layout>
Resulting class:
`container flex justify-center items-center min-h-screen`
#### Example 2: Custom Behavior
Pass a custom class:
<Layout content-class="flex flex-col items-center justify-start">
<h1 class="text-4xl font-bold">Welcome to the Page</h1>
</Layout>
Resulting class:
`container flex flex-col items-center justify-start`
### Benefits
– Ensures `container` is always present.
– Keeps the layout flexible by allowing custom classes for specific pages.
—
### 1. **Looping Through an Array**
<template>
<ul>
<li v-for="(item, index) in items" :key="index">
{{ index + 1 }}. {{ item }}
</li>
</ul>
</template>
<script setup>
const items = ['Apple', 'Banana', 'Cherry'];
</script>
**Explanation**:
– `v-for="(item, index) in items"` loops over the array `items`.
– `item` represents each element in the array.
– `index` provides the position of the element.
—
### 2. **Looping Through an Object**
<template>
<ul>
<li v-for="(value, key, index) in user" :key="key">
{{ index + 1 }}. {{ key }}: {{ value }}
</li>
</ul>
</template>
<script setup>
const user = {
name: 'John Doe',
age: 30,
email: 'john.doe@example.com',
};
</script>
**Explanation**:
– `v-for="(value, key, index) in user"` loops over the object `user`.
– `key` refers to the property name (e.g., `name`, `age`).
– `value` refers to the property value (e.g., `John Doe`, `30`).
—
### 3. **Looping Through a Range of Numbers**
<template>
<ul>
<li v-for="number in 5" :key="number">
Item {{ number }}
</li>
</ul>
</template>
**Explanation**:
– `v-for="number in 5"` loops 5 times, generating numbers from `1` to `5`.
—
### 4. **Nested Loops**
<template>
<div v-for="(row, rowIndex) in grid" :key="rowIndex">
<p>Row {{ rowIndex + 1 }}:</p>
<ul>
<li v-for="(col, colIndex) in row" :key="colIndex">
Column {{ colIndex + 1 }}: {{ col }}
</li>
</ul>
</div>
</template>
<script setup>
const grid = [
['A1', 'A2', 'A3'],
['B1', 'B2', 'B3'],
['C1', 'C2', 'C3'],
];
</script>
**Explanation**:
– Outer loop iterates through `grid` rows.
– Inner loop iterates through each row's columns.
—
### 5. **Conditionals with `v-for`**
You can combine `v-if` with `v-for`, but it's recommended to avoid putting `v-if` directly on the same element. Instead, wrap it in a parent tag or use computed properties.
<template>
<ul>
<li v-for="(item, index) in filteredItems" :key="index">
{{ item }}
</li>
</ul>
</template>
<script setup>
const items = ['Apple', 'Banana', 'Cherry', 'Date'];
const filteredItems = items.filter(item => item.startsWith('B'));
</script>
—
### 6. **Handling an Empty List**
<template>
<div>
<p v-if="items.length === 0">No items available.</p>
<ul v-else>
<li v-for="(item, index) in items" :key="index">
{{ item }}
</li>
</ul>
</div>
</template>
<script setup>
const items = [];
</script>
—
### Key Points
1. Always use the `:key` attribute in `v-for` for optimal rendering performance.
2. Use computed properties or filters when combining `v-if` with `v-for` to avoid performance issues.
3. The `v-for` directive supports arrays, objects, and ranges.
Here's how to use `v-html` to display HTML content in a Vue component:
### Example of Using `v-html`
<template>
<div>
<h1>My HTML Content</h1>
<div v-html="htmlContent"></div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const htmlContent = ref(`
<p>This is <strong>bold</strong> text and this is <em>italic</em> text.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
`);
</script>
### Explanation
1. **Template**:
– The `v-html` directive is applied to a “. It binds to the `htmlContent` variable.
– The rendered HTML will include any valid HTML tags and styling.
2. **Script Setup**:
– The `htmlContent` variable is created using `ref()` to make it reactive.
– It contains a string with HTML markup, which can include paragraphs, lists, and other HTML elements.
### Important Considerations
– **Sanitization**: Before displaying HTML from an untrusted source, ensure it is sanitized to prevent XSS attacks. Libraries like `DOMPurify` can help sanitize HTML content.
**Example of Using `DOMPurify`:**
First, install `DOMPurify`:
npm install dompurify
Then, import and use it in your component:
<template>
<div>
<h1>My Safe HTML Content</h1>
<div v-html="sanitizedHtmlContent"></div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import DOMPurify from 'dompurify';
const rawHtmlContent = ref(`
<p>This is <strong>bold</strong> text and this is <em>italic</em> text.</p>
<script>alert('XSS Attack!');</script> <!-- This will be removed -->
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
`);
const sanitizedHtmlContent = computed(() => {
return DOMPurify.sanitize(rawHtmlContent.value);
});
</script>
**Explanation**:
– `rawHtmlContent` contains the original HTML, including potentially harmful scripts.
– `sanitizedHtmlContent` uses `DOMPurify` to sanitize the raw HTML before rendering it.
### Conclusion
Using `v-html` in Vue allows you to dynamically render HTML content. Always ensure the content is sanitized if it comes from an untrusted source to protect your application from XSS vulnerabilities.
### Example Structure
Here's a simple example of how to create a layout with three cards per row using Tailwind CSS:
<template>
<div class="container mx-auto p-4">
<h2 class="text-2xl font-semibold mb-4">Card Layout</h2>
<div class="flex flex-wrap justify-center">
<div class="card w-full sm:w-1/2 md:w-1/3 p-4">
<div class="border border-gray-300 rounded-lg p-4 shadow">
<h3 class="text-lg font-bold mb-2">Card Title 1</h3>
<p>This is a description for card 1.</p>
</div>
</div>
<div class="card w-full sm:w-1/2 md:w-1/3 p-4">
<div class="border border-gray-300 rounded-lg p-4 shadow">
<h3 class="text-lg font-bold mb-2">Card Title 2</h3>
<p>This is a description for card 2.</p>
</div>
</div>
<div class="card w-full sm:w-1/2 md:w-1/3 p-4">
<div class="border border-gray-300 rounded-lg p-4 shadow">
<h3 class="text-lg font-bold mb-2">Card Title 3</h3>
<p>This is a description for card 3.</p>
</div>
</div>
<!-- Add more cards as needed -->
</div>
</div>
</template>
<script setup>
// You can add any necessary logic here
</script>
<style scoped>
.card {
transition: transform 0.2s;
}
.card:hover {
transform: scale(1.05);
}
</style>
### Explanation
1. **Container**:
– `container mx-auto p-4`: Centers the container and adds padding.
2. **Flexbox Layout**:
– `flex flex-wrap justify-center`: Creates a flex container that wraps items and centers them.
3. **Cards**:
– Each card has the class `w-full sm:w-1/2 md:w-1/3 p-4`, which:
– `w-full`: Takes full width on extra-small screens.
– `sm:w-1/2`: Takes half width on small screens (2 cards per row).
– `md:w-1/3`: Takes one-third width on medium and larger screens (3 cards per row).
– `p-4`: Adds padding inside the card.
4. **Card Styling**:
– Each card has a border, rounded corners, padding, and a shadow for a nice card effect.
5. **Hover Effect**:
– The card scales slightly when hovered over to give a visual cue.
### Responsive Behavior
– On extra-small screens (mobile), cards will stack vertically (1 card per row).
– On small screens, 2 cards will be displayed per row.
– On medium and larger screens, 3 cards will be displayed per row.
### Adding More Cards
To add more cards, simply replicate the card `div` structure inside the flex container. The layout will adjust automatically based on the screen size.