# Container

> Max-width content wrapper with responsive horizontal padding.

- Status: stable
- Group: layout
- Page: https://www.digitaltableteur.com/design-system/components/container
- Contract: https://www.digitaltableteur.com/contracts/v1/Container.contract.json

## When to use

Container clamps content to a readable page width and centers it. Pick `size` by the content's measure, not the viewport: `lg` (1200px) is the page default, `sm` suits prose. It renders a `div` unless you pass `as` (use `main` when the wrapper should also be the main landmark; a `section` is only a region landmark when it has an accessible name, so pass `aria-label` or `aria-labelledby` with it; other HTML attributes are forwarded too). One container per page region; sections stack inside it, not around it.

## When not to use

- Do not nest a Container inside another Container; gutters compound and the measure narrows.
- Do not use size="full" together with a custom max-width class; pick the size that matches instead.
- Do not use size="full" plus a custom max-width class; pick the size that matches instead.

## Look-alikes

- Center: Do not use Center as a page layout root; that is Container + Section.

## Props

| Prop | Type | Default | Description | Required |
| --- | --- | --- | --- | --- |
| `children` | `ReactNode` | none | Page content inside the width constraint. | Yes |
| `size` | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `lg` | Max-width token. Defaults to `lg`. | No |
| `center` | `boolean` | `true` | Center the container horizontally. Defaults to `true`. | No |
| `className` | `string` | none | Wrapper class names. | No |
| `as` | `"symbol" \| "object" \| "image" \| "form" \| "slot" \| "style" \| "title" \| "button" \| "search" \| "article" \| "dialog" \| "figure" \| "img" \| "link" \| "main" \| "menu" \| "menuitem" \| "option" \| "switch" \| "table" \| "text" \| "time" \| "div" \| "section" \| "aside" \| "li" \| "a" \| "abbr" \| "address" \| "area" \| "audio" \| "b" \| "base" \| "bdi" \| "bdo" \| "big" \| "blockquote" \| "body" \| "br" \| "canvas" \| "caption" \| "center" \| "cite" \| "code" \| "col" \| "colgroup" \| "data" \| "datalist" \| "dd" \| "del" \| "details" \| "dfn" \| "dl" \| "dt" \| "em" \| "embed" \| "fieldset" \| "figcaption" \| "footer" \| "h1" \| "h2" \| "h3" \| "h4" \| "h5" \| "h6" \| "head" \| "header" \| "hgroup" \| "hr" \| "html" \| "i" \| "iframe" \| "input" \| "ins" \| "kbd" \| "keygen" \| "label" \| "legend" \| "map" \| "mark" \| "meta" \| "meter" \| "nav" \| "noindex" \| "noscript" \| "ol" \| "optgroup" \| "output" \| "p" \| "param" \| "picture" \| "pre" \| "progress" \| "q" \| "rp" \| "rt" \| "ruby" \| "s" \| "samp" \| "script" \| "select" \| "small" \| "source" \| "span" \| "strong" \| "sub" \| "summary" \| "sup" \| "template" \| "tbody" \| "td" \| "textarea" \| "tfoot" \| "th" \| "thead" \| "tr" \| "track" \| "u" \| "ul" \| "var" \| "video" \| "wbr" \| "webview" \| "svg" \| "animate" \| "animateMotion" \| "animateTransform" \| "circle" \| "clipPath" \| "defs" \| "desc" \| "ellipse" \| "feBlend" \| "feColorMatrix" \| "feComponentTransfer" \| "feComposite" \| "feConvolveMatrix" \| "feDiffuseLighting" \| "feDisplacementMap" \| "feDistantLight" \| "feDropShadow" \| "feFlood" \| "feFuncA" \| "feFuncB" \| "feFuncG" \| "feFuncR" \| "feGaussianBlur" \| "feImage" \| "feMerge" \| "feMergeNode" \| "feMorphology" \| "feOffset" \| "fePointLight" \| "feSpecularLighting" \| "feSpotLight" \| "feTile" \| "feTurbulence" \| "filter" \| "foreignObject" \| "g" \| "line" \| "linearGradient" \| "marker" \| "mask" \| "metadata" \| "mpath" \| "path" \| "pattern" \| "polygon" \| "polyline" \| "radialGradient" \| "rect" \| "set" \| "stop" \| "textPath" \| "tspan" \| "use" \| "view"` | `div` | Polymorphic element. Defaults to `div`. Typed as any React ElementType, so the values list is every JSX intrinsic; only container elements (div, main, section, article, aside, header, footer) make sense here. | No |

## Variants

- Available sizes: `sm`, `md`, `lg`, `xl`, `full` (default `lg`).
- Allowed `as` values: `symbol`, `object`, `image`, `form`, `slot`, `style`, `title`, `button`, `search`, `article`, `dialog`, `figure`, `img`, `link`, `main`, `menu`, `menuitem`, `option`, `switch`, `table`, `text`, `time`, `div`, `section`, `aside`, `li`, `a`, `abbr`, `address`, `area`, `audio`, `b`, `base`, `bdi`, `bdo`, `big`, `blockquote`, `body`, `br`, `canvas`, `caption`, `center`, `cite`, `code`, `col`, `colgroup`, `data`, `datalist`, `dd`, `del`, `details`, `dfn`, `dl`, `dt`, `em`, `embed`, `fieldset`, `figcaption`, `footer`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hgroup`, `hr`, `html`, `i`, `iframe`, `input`, `ins`, `kbd`, `keygen`, `label`, `legend`, `map`, `mark`, `meta`, `meter`, `nav`, `noindex`, `noscript`, `ol`, `optgroup`, `output`, `p`, `param`, `picture`, `pre`, `progress`, `q`, `rp`, `rt`, `ruby`, `s`, `samp`, `script`, `select`, `small`, `source`, `span`, `strong`, `sub`, `summary`, `sup`, `template`, `tbody`, `td`, `textarea`, `tfoot`, `th`, `thead`, `tr`, `track`, `u`, `ul`, `var`, `video`, `wbr`, `webview`, `svg`, `animate`, `animateMotion`, `animateTransform`, `circle`, `clipPath`, `defs`, `desc`, `ellipse`, `feBlend`, `feColorMatrix`, `feComponentTransfer`, `feComposite`, `feConvolveMatrix`, `feDiffuseLighting`, `feDisplacementMap`, `feDistantLight`, `feDropShadow`, `feFlood`, `feFuncA`, `feFuncB`, `feFuncG`, `feFuncR`, `feGaussianBlur`, `feImage`, `feMerge`, `feMergeNode`, `feMorphology`, `feOffset`, `fePointLight`, `feSpecularLighting`, `feSpotLight`, `feTile`, `feTurbulence`, `filter`, `foreignObject`, `g`, `line`, `linearGradient`, `marker`, `mask`, `metadata`, `mpath`, `path`, `pattern`, `polygon`, `polyline`, `radialGradient`, `rect`, `set`, `stop`, `textPath`, `tspan`, `use`, `view` (default `div`).

## Invalid combinations

The contract records no invalid combinations.

## Keyboard

The contract records no keyboard interaction.

## Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

| Level | Rule | How it is checked |
| --- | --- | --- |
| MUST | ARIA: Container forwards other HTML attributes (aria-label, aria-labelledby, id, role, data-*) to the rendered element, so as="section" with an aria-label or aria-labelledby is a named region landmark. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by `npm run test:stories:matrix:ci`. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by `npm run test:stories:matrix:ci`. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by `npm run test:stories:hc`. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Pick size by content measure: sm for prose, lg for standard pages, xl only for dashboard-density layouts. | Not stated in the contract. |
| SHOULD | Use as="main" when the container doubles as the main landmark, instead of nesting an extra wrapper. as="section" is a region landmark only with an aria-label or aria-labelledby, which Container forwards. | Not stated in the contract. |
| SHOULD | Pair with Section: Section owns vertical rhythm and background, Container owns horizontal clamp. | Not stated in the contract. |
| SHOULD | Keep center on (default); opt out only for asymmetric editorial layouts. | Not stated in the contract. |
| SHOULD NOT | Do not nest containers; you get compounding gutters and a narrowing measure. | Not stated in the contract. |

## Install and import

- Install: `npm install @digitaltableteur/react` (version 0.9.1, restricted access on npm).
- Import: `import { Container } from "@digitaltableteur/react";`
- Entry point: `@digitaltableteur/react/layout` exports it too.
- Styles: import `@digitaltableteur/react/style.css` once at the app boundary.
- Also available as the custom element `<dt-container>`; see the custom elements manifest.

## Links

- Machine-readable contract (Design System Contract 1.0): https://www.digitaltableteur.com/contracts/v1/Container.contract.json
- Markdown version of this page: https://www.digitaltableteur.com/design-system/components/container.md
- Component index as JSON: https://www.digitaltableteur.com/design-system/components.json
- All components: https://www.digitaltableteur.com/design-system/components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.
