Skip to content

Container

A container lets you center and constrain the width of your content.

Demo

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae numquam quod excepturi rerum vel quos? Fugit ut quidem sit odit facilis, perferendis sunt, expedita quo deserunt dolorum eligendi pariatur commodi?

This requires the following theme to be installed:

Component

Container.vue
vue
<script lang="ts">
import theme from '@/ui/theme/container'
import { Primitive } from 'reka-ui'
import { tv } from 'tailwind-variants'

const container = tv(theme)

export interface ContainerProps {
  as?: any
  class?: any
}

export interface ContainerSlots {
  default: (props?: object) => any
}
</script>

<script setup lang="ts">
const props = withDefaults(defineProps<ContainerProps>(), {
  as: 'div',
})
defineSlots<ContainerSlots>()
</script>

<template>
  <Primitive :as="as" :class="container({ class: props.class })">
    <slot />
  </Primitive>
</template>
Container.vue
vue
<script lang="ts">
import theme from '@/UI/Theme/container'
import { Primitive } from 'reka-ui'
import { tv } from 'tailwind-variants'

const container = tv(theme)

export interface ContainerProps {
  as?: any
  class?: any
}

export interface ContainerSlots {
  default: (props?: object) => any
}
</script>

<script setup lang="ts">
const props = withDefaults(defineProps<ContainerProps>(), {
  as: 'div',
})
defineSlots<ContainerSlots>()
</script>

<template>
  <Primitive :as="as" :class="container({ class: props.class })">
    <slot />
  </Primitive>
</template>

Theme

container.ts
ts
export default {
  base: '',
}
View Nuxt UI theme
container.ts
ts
export default {
  base: 'max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8',
}

Test

To test this component, you can use the following test file:

Container.test.ts
ts
import type { RenderOptions } from '@testing-library/vue'
import Container from '@/ui/components/Container.vue'
import { render, screen } from '@testing-library/vue'
import { describe, expect, it } from 'vitest'

describe('container', () => {
  it.each<[string, RenderOptions<typeof Container>]>([
    // Props
    ['with as', { props: { as: 'article' } }],
    ['with class', { props: { class: 'max-w-5xl' } }],
    // Slots
    ['with default slot', { slots: { default: () => 'Default slot' } }],
  ])(`renders %s correctly`, (name, options) => {
    render(Container, {
      attrs: {
        'data-testid': 'container',
      },
      ...options,
    })

    expect(screen.getByTestId('container')).toMatchSnapshot()
  })
})
Container.test.ts
ts
import type { RenderOptions } from '@testing-library/vue'
import Container from '@/UI/Components/Container.vue'
import { render, screen } from '@testing-library/vue'
import { describe, expect, it } from 'vitest'

describe('container', () => {
  it.each<[string, RenderOptions<typeof Container>]>([
    // Props
    ['with as', { props: { as: 'article' } }],
    ['with class', { props: { class: 'max-w-5xl' } }],
    // Slots
    ['with default slot', { slots: { default: () => 'Default slot' } }],
  ])(`renders %s correctly`, (name, options) => {
    render(Container, {
      attrs: {
        'data-testid': 'container',
      },
      ...options,
    })

    expect(screen.getByTestId('container')).toMatchSnapshot()
  })
})

Contributors

barbapapazes

Changelog

c615c - feat: add custom eslint rule to disallow relative imports (#81) on 1/7/2025
5f2d8 - feat: add container component (#95) on 1/2/2025