Container Components
Proton provides several container components for organizing and structuring content in consistent layouts.
Location: components/container/
Row
Horizontal row container for grouping elements.
Location: components/container/Row.tsx
Usage
import Row from '@proton/components/components/container/Row';
const MyLayout = () => {
return (
<Row>
<div>Column 1</div>
<div>Column 2</div>
</Row>
);
};
Props
Extends standard HTML div attributes.
Content to display in the row
Field
Form field container.
Location: components/container/Field.tsx
Usage
import Field from '@proton/components/components/container/Field';
import Input from '@proton/components/components/input/Input';
const MyForm = () => {
return (
<Field>
<label>Email</label>
<Input type="email" />
</Field>
);
};
Bordered
Container with border styling.
Location: components/container/Bordered.tsx
Usage
import Bordered from '@proton/components/components/container/Bordered';
const MyCard = () => {
return (
<Bordered>
<h3>Card Title</h3>
<p>Card content goes here</p>
</Bordered>
);
};
Props
Details
Collapsible details container.
Location: components/container/Details.tsx
Usage
import Details from '@proton/components/components/container/Details';
import Summary from '@proton/components/components/container/Summary';
const MyCollapsible = () => {
return (
<Details>
<Summary>Click to expand</Summary>
<div>Hidden content that appears when expanded</div>
</Details>
);
};
Props
Whether details is initially open
Callback when details is toggled
Summary
Summary component for Details.
Location: components/container/Summary.tsx
Usage
import Summary from '@proton/components/components/container/Summary';
<Summary>Summary text</Summary>
EditableSection
Section with edit mode toggle.
Location: components/container/EditableSection.tsx
Usage
import EditableSection from '@proton/components/components/container/EditableSection';
import { Button } from '@proton/atoms/Button/Button';
const MyEditableSection = () => {
const [editing, setEditing] = useState(false);
return (
<EditableSection>
<div className="flex justify-between">
<h3>Profile Information</h3>
<Button onClick={() => setEditing(!editing)}>
{editing ? 'Save' : 'Edit'}
</Button>
</div>
{editing ? (
<div>
{/* Edit form */}
</div>
) : (
<div>
{/* Display content */}
</div>
)}
</EditableSection>
);
};
Examples
Best Practices
Consistent Spacing
Use container components for consistent spacing:
<div className="flex flex-column gap-4">
<Row className="gap-4">
<Field className="flex-1">
<label>First Name</label>
<Input />
</Field>
<Field className="flex-1">
<label>Last Name</label>
<Input />
</Field>
</Row>
<Row>
<Field className="w-full">
<label>Email</label>
<Input type="email" fullWidth />
</Field>
</Row>
</div>
Responsive Layouts
<Row className="flex-column md:flex-row gap-4">
<Field className="flex-1">
<label>Field 1</label>
<Input />
</Field>
<Field className="flex-1">
<label>Field 2</label>
<Input />
</Field>
</Row>
Nested Containers
<Bordered className="p-4">
<h2 className="mb-4">Section Title</h2>
<Details>
<Summary>Subsection 1</Summary>
<Row className="p-4">
<Field>
<label>Field</label>
<Input />
</Field>
</Row>
</Details>
<Details>
<Summary>Subsection 2</Summary>
<div className="p-4">
{/* Content */}
</div>
</Details>
</Bordered>
Common Patterns
Two-Column Layout
const TwoColumnLayout = () => {
return (
<Row className="gap-8">
<div className="flex-1">
<h3>Left Column</h3>
<p>Content for left side</p>
</div>
<div className="flex-1">
<h3>Right Column</h3>
<p>Content for right side</p>
</div>
</Row>
);
};
Settings Layout
const SettingsLayout = () => {
return (
<div className="flex flex-column gap-4">
<Bordered className="p-4">
<Details>
<Summary>General Settings</Summary>
<div className="p-4">
<Row className="gap-4">
<Field>
<label>Username</label>
<Input />
</Field>
<Field>
<label>Display Name</label>
<Input />
</Field>
</Row>
</div>
</Details>
</Bordered>
<Bordered className="p-4">
<Details>
<Summary>Privacy Settings</Summary>
<div className="p-4">
{/* Privacy settings */}
</div>
</Details>
</Bordered>
</div>
);
};
Card Grid
const CardGrid = ({ items }) => {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{items.map(item => (
<Bordered key={item.id} className="p-4">
<h3>{item.title}</h3>
<p>{item.description}</p>
</Bordered>
))}
</div>
);
};
Source Code
View source:
- Row:
packages/components/components/container/Row.tsx:1
- Field:
packages/components/components/container/Field.tsx:1
- Bordered:
packages/components/components/container/Bordered.tsx:1
- Details:
packages/components/components/container/Details.tsx:1