name: layout-patterns description: Common UI layout patterns using fundamental-styles - login forms, dashboards, master-detail, wizards, and more metadata: tags: ['patterns', 'layouts', 'examples', 'templates']
Layout Patterns Skill
This skill provides common UI layout patterns using fundamental-styles components. Use this to build complete, production-ready interfaces by combining multiple components correctly.
When to Use This Skill
Use this skill when:
- The user asks "How do I build a [pattern name]?"
- The user needs to combine multiple components
- The user wants a complete working example
- The user asks about common UI patterns (login, dashboard, master-detail, etc.)
Pattern 1: Login Form
A complete login form with email/password fields, validation, and action buttons.
Components used:
fd-form-item- Form field containersfd-form-label- Field labelsfd-input- Text inputsfd-button- Action buttonsfd-message-strip- Error feedback
When to use:
- Authentication pages
- Sign-in forms
- User credential entry
Complete example:
<div style="max-width: 400px; margin: 2rem auto;">
<!-- Error message (hidden by default) -->
<div class="fd-message-strip fd-message-strip--error" role="alert" style="display: none;" id="login-error">
<p class="fd-message-strip__text">Invalid email or password. Please try again.</p>
</div>
<form>
<!-- Email field -->
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="email"> Email </label>
<input
class="fd-input"
type="email"
id="email"
placeholder="name@example.com"
required
aria-required="true"
/>
</div>
<!-- Password field -->
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="password"> Password </label>
<input
class="fd-input"
type="password"
id="password"
placeholder="Enter your password"
required
aria-required="true"
/>
</div>
<!-- Action buttons -->
<div class="fd-form-item">
<button class="fd-button fd-button--emphasized" type="submit" style="width: 100%;">Sign In</button>
</div>
<div class="fd-form-item" style="text-align: center;">
<a href="#" class="fd-link">Forgot password?</a>
</div>
</form>
</div>
Key points:
- Use
fd-form-label--requiredfor required fields - Add
aria-required="true"for accessibility - Use
fd-button--emphasizedfor the primary action - Hide error message by default, show with JavaScript on validation failure
- Use semantic HTML5 input types (
email,password)
Pattern 2: Master-Detail Layout
A two-column layout with a master list on the left and detail panel on the right. Clicking an item in the master list shows its details.
Components used:
fd-list- Master list (left)fd-panel- Detail panel (right)fd-toolbar- Actions barfd-button- Action buttons
When to use:
- Email clients (inbox + message detail)
- File browsers (folders + file preview)
- Settings pages (categories + options)
- Any list-detail relationship
Complete example:
<div style="display: flex; gap: 1rem; height: 600px;">
<!-- Master (List) -->
<div style="flex: 0 0 300px; overflow-y: auto; border-right: 1px solid var(--sapGroup_ContentBorderColor);">
<ul class="fd-list" role="listbox">
<li class="fd-list__item is-selected" role="option" tabindex="0">
<div class="fd-list__content">
<div class="fd-list__title">Item 1</div>
<div class="fd-list__byline">Last updated 2 hours ago</div>
</div>
</li>
<li class="fd-list__item" role="option" tabindex="-1">
<div class="fd-list__content">
<div class="fd-list__title">Item 2</div>
<div class="fd-list__byline">Last updated 5 hours ago</div>
</div>
</li>
<li class="fd-list__item" role="option" tabindex="-1">
<div class="fd-list__content">
<div class="fd-list__title">Item 3</div>
<div class="fd-list__byline">Last updated yesterday</div>
</div>
</li>
</ul>
</div>
<!-- Detail (Panel) -->
<div style="flex: 1; overflow-y: auto;">
<div class="fd-panel">
<!-- Toolbar with actions -->
<div class="fd-toolbar">
<div class="fd-toolbar__group">
<button class="fd-button fd-button--transparent fd-button--compact">
<i class="sap-icon--edit" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Edit</span>
</button>
<button class="fd-button fd-button--transparent fd-button--compact">
<i class="sap-icon--delete" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Delete</span>
</button>
<button class="fd-button fd-button--transparent fd-button--compact">
<i class="sap-icon--share" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Share</span>
</button>
</div>
</div>
<!-- Panel header -->
<div class="fd-panel__header">
<h3 class="fd-panel__title">Item 1 Details</h3>
<p class="fd-panel__description">View and manage item information</p>
</div>
<!-- Panel body -->
<div class="fd-panel__body">
<div class="fd-form-item">
<label class="fd-form-label">Name</label>
<p>Item 1</p>
</div>
<div class="fd-form-item">
<label class="fd-form-label">Status</label>
<p>Active</p>
</div>
<div class="fd-form-item">
<label class="fd-form-label">Description</label>
<p>
This is a detailed description of Item 1. It contains information about the item's properties,
history, and current state.
</p>
</div>
</div>
</div>
</div>
</div>
Key points:
- Use flexbox for the two-column layout
- Set fixed width for master (e.g.,
300px) - Use
is-selectedclass on active list item - Add
overflow-y: autofor scrollable panels - Use
fd-toolbarfor detail panel actions - Implement keyboard navigation (arrow keys) for list items
Pattern 3: Data Table with Actions
A table with selectable rows, bulk actions toolbar, and per-row action buttons.
Components used:
fd-table- Data gridfd-checkbox- Row selectionfd-toolbar- Bulk actionsfd-button- Action buttons
When to use:
- User management tables
- Product catalogs
- Order lists
- Any data that needs bulk operations
Complete example:
<!-- Toolbar with bulk actions (shown when rows are selected) -->
<div class="fd-toolbar">
<div class="fd-toolbar__group">
<span class="fd-toolbar__label">2 items selected</span>
</div>
<div class="fd-toolbar__group">
<button class="fd-button fd-button--transparent fd-button--compact">
<i class="sap-icon--delete" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Delete Selected</span>
</button>
<button class="fd-button fd-button--transparent fd-button--compact">
<i class="sap-icon--email" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Send Email</span>
</button>
</div>
</div>
<!-- Table -->
<table class="fd-table">
<thead class="fd-table__header">
<tr class="fd-table__row">
<th class="fd-table__cell" style="width: 50px;">
<input type="checkbox" class="fd-checkbox" id="select-all" aria-label="Select all rows" />
<label class="fd-checkbox__label" for="select-all"></label>
</th>
<th class="fd-table__cell" scope="col">Name</th>
<th class="fd-table__cell" scope="col">Email</th>
<th class="fd-table__cell" scope="col">Status</th>
<th class="fd-table__cell" scope="col">Actions</th>
</tr>
</thead>
<tbody class="fd-table__body">
<tr class="fd-table__row is-selected">
<td class="fd-table__cell">
<input type="checkbox" class="fd-checkbox" id="row1" checked aria-label="Select row 1" />
<label class="fd-checkbox__label" for="row1"></label>
</td>
<td class="fd-table__cell">John Doe</td>
<td class="fd-table__cell">john.doe@example.com</td>
<td class="fd-table__cell">
<span class="fd-object-status fd-object-status--positive">Active</span>
</td>
<td class="fd-table__cell">
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Edit John Doe">
<i class="sap-icon--edit"></i>
</button>
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Delete John Doe">
<i class="sap-icon--delete"></i>
</button>
</td>
</tr>
<tr class="fd-table__row is-selected">
<td class="fd-table__cell">
<input type="checkbox" class="fd-checkbox" id="row2" checked aria-label="Select row 2" />
<label class="fd-checkbox__label" for="row2"></label>
</td>
<td class="fd-table__cell">Jane Smith</td>
<td class="fd-table__cell">jane.smith@example.com</td>
<td class="fd-table__cell">
<span class="fd-object-status fd-object-status--critical">Inactive</span>
</td>
<td class="fd-table__cell">
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Edit Jane Smith">
<i class="sap-icon--edit"></i>
</button>
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Delete Jane Smith">
<i class="sap-icon--delete"></i>
</button>
</td>
</tr>
<tr class="fd-table__row">
<td class="fd-table__cell">
<input type="checkbox" class="fd-checkbox" id="row3" aria-label="Select row 3" />
<label class="fd-checkbox__label" for="row3"></label>
</td>
<td class="fd-table__cell">Bob Johnson</td>
<td class="fd-table__cell">bob.johnson@example.com</td>
<td class="fd-table__cell">
<span class="fd-object-status fd-object-status--positive">Active</span>
</td>
<td class="fd-table__cell">
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Edit Bob Johnson">
<i class="sap-icon--edit"></i>
</button>
<button class="fd-button fd-button--transparent fd-button--compact" aria-label="Delete Bob Johnson">
<i class="sap-icon--delete"></i>
</button>
</td>
</tr>
</tbody>
</table>
Key points:
- Use
fd-checkboxin first column for row selection - Add
is-selectedclass to selected rows - Show/hide toolbar based on selection state
- Use
fd-button--compactfor in-table actions - Add descriptive
aria-labelfor icon-only buttons - Use
fd-object-statusfor semantic status indicators
Pattern 4: Multi-Step Wizard
A step-by-step wizard for complex forms or processes.
Components used:
fd-wizard- Stepper navigationfd-form-item- Form fieldsfd-input- Input fieldsfd-button- Navigation buttons
When to use:
- Multi-step forms (signup, checkout, configuration)
- Guided workflows
- Setup wizards
- Complex data entry processes
Complete example:
<div style="max-width: 800px; margin: 2rem auto;">
<!-- Wizard navigation -->
<div class="fd-wizard">
<nav class="fd-wizard__navigation">
<ul class="fd-wizard__steps">
<li class="fd-wizard__step fd-wizard__step--completed">
<div class="fd-wizard__step-wrapper">
<span class="fd-wizard__step-indicator">
<i class="sap-icon--accept"></i>
</span>
<div class="fd-wizard__step-content">
<span class="fd-wizard__label">Personal Info</span>
</div>
</div>
</li>
<li class="fd-wizard__step fd-wizard__step--current">
<div class="fd-wizard__step-wrapper">
<span class="fd-wizard__step-indicator">2</span>
<div class="fd-wizard__step-content">
<span class="fd-wizard__label">Contact Details</span>
</div>
</div>
</li>
<li class="fd-wizard__step">
<div class="fd-wizard__step-wrapper">
<span class="fd-wizard__step-indicator">3</span>
<div class="fd-wizard__step-content">
<span class="fd-wizard__label">Review</span>
</div>
</div>
</li>
</ul>
</nav>
</div>
<!-- Step content -->
<div class="fd-wizard__content" style="margin-top: 2rem;">
<h3>Step 2: Contact Details</h3>
<p style="margin-bottom: 1rem;">Please provide your contact information.</p>
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="phone"> Phone Number </label>
<input class="fd-input" type="tel" id="phone" placeholder="+1 (555) 123-4567" required />
</div>
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="email-wizard"> Email </label>
<input class="fd-input" type="email" id="email-wizard" placeholder="name@example.com" required />
</div>
<div class="fd-form-item">
<label class="fd-form-label" for="address"> Address </label>
<textarea class="fd-textarea" id="address" rows="3" placeholder="Enter your address"></textarea>
</div>
</div>
<!-- Navigation buttons -->
<div class="fd-wizard__footer" style="margin-top: 2rem; display: flex; justify-content: space-between;">
<button class="fd-button fd-button--transparent">
<i class="sap-icon--slim-arrow-left" role="presentation" aria-hidden="true"></i>
<span class="fd-button__text">Previous</span>
</button>
<button class="fd-button fd-button--emphasized">
<span class="fd-button__text">Next</span>
<i class="sap-icon--slim-arrow-right" role="presentation" aria-hidden="true"></i>
</button>
</div>
</div>
Key points:
- Use
fd-wizard__step--completedfor finished steps - Use
fd-wizard__step--currentfor active step - Show only the current step's content
- Validate current step before allowing "Next"
- Use "Previous" and "Next" buttons for navigation
- Change "Next" to "Finish" on the last step
- Implement keyboard navigation (arrow keys optional)
Pattern 5: Form with Validation
A complete form with field validation, error messages, and proper accessibility.
Components used:
fd-form-item- Form field containersfd-form-label- Labelsfd-input- Text inputsfd-select- Dropdownsfd-form-message- Validation messagesfd-button- Submit button
When to use:
- User registration forms
- Profile editing
- Data entry forms
- Any form requiring validation
Complete example:
<form style="max-width: 600px;">
<!-- Valid field -->
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="username"> Username </label>
<input class="fd-input is-success" type="text" id="username" value="john.doe" aria-invalid="false" />
<span class="fd-form-message fd-form-message--success"> Username is available </span>
</div>
<!-- Invalid field -->
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="email-form"> Email </label>
<input
class="fd-input is-error"
type="email"
id="email-form"
value="invalid-email"
aria-invalid="true"
aria-describedby="email-error"
/>
<span class="fd-form-message fd-form-message--error" id="email-error">
Please enter a valid email address
</span>
</div>
<!-- Warning field -->
<div class="fd-form-item">
<label class="fd-form-label" for="password-form"> Password </label>
<input
class="fd-input is-warning"
type="password"
id="password-form"
value="weak"
aria-describedby="password-warning"
/>
<span class="fd-form-message fd-form-message--warning" id="password-warning">
Password is weak. Consider using a stronger password.
</span>
</div>
<!-- Information field -->
<div class="fd-form-item">
<label class="fd-form-label" for="bio"> Bio </label>
<textarea class="fd-textarea is-information" id="bio" rows="3" aria-describedby="bio-info"></textarea>
<span class="fd-form-message fd-form-message--information" id="bio-info">
Tell us a bit about yourself (optional, max 500 characters)
</span>
</div>
<!-- Select dropdown -->
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="country"> Country </label>
<select class="fd-select" id="country" required>
<option value="">Select a country</option>
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="ca">Canada</option>
</select>
</div>
<!-- Submit button -->
<div class="fd-form-item">
<button class="fd-button fd-button--emphasized" type="submit">Save Changes</button>
<button class="fd-button fd-button--transparent" type="button">Cancel</button>
</div>
</form>
Key points:
- Use state classes:
is-error,is-success,is-warning,is-information - Pair states with matching
fd-form-messagecomponents - Link messages to inputs with
aria-describedby - Set
aria-invalid="true"for error states - Mark required fields with
fd-form-label--required - Validate on blur, not on every keystroke (better UX)
- Disable submit button until form is valid
Pattern 6: Dialog with Form
A modal dialog containing a form for focused data entry.
Components used:
fd-dialog- Modal containerfd-bar- Header and footerfd-form-item- Form fieldsfd-button- Actions
When to use:
- Quick data entry without leaving current page
- Edit existing records
- Create new records in context
- Focused user input
Complete example:
<div class="fd-dialog fd-dialog--active" role="dialog" aria-modal="true" aria-labelledby="dialog-form-title">
<div class="fd-dialog__content" style="width: 500px;">
<!-- Header -->
<header class="fd-dialog__header fd-bar fd-bar--header">
<div class="fd-bar__left">
<div class="fd-bar__element">
<h3 class="fd-title fd-title--h5" id="dialog-form-title">Create New User</h3>
</div>
</div>
<div class="fd-bar__right">
<div class="fd-bar__element">
<button class="fd-button fd-button--transparent" aria-label="Close">
<i class="sap-icon--decline"></i>
</button>
</div>
</div>
</header>
<!-- Body with form -->
<div class="fd-dialog__body">
<form id="user-form">
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="dialog-name"> Full Name </label>
<input class="fd-input" type="text" id="dialog-name" placeholder="Enter full name" required />
</div>
<div class="fd-form-item">
<label class="fd-form-label fd-form-label--required" for="dialog-email"> Email </label>
<input class="fd-input" type="email" id="dialog-email" placeholder="name@example.com" required />
</div>
<div class="fd-form-item">
<label class="fd-form-label" for="dialog-role"> Role </label>
<select class="fd-select" id="dialog-role">
<option value="user">User</option>
<option value="admin">Administrator</option>
<option value="editor">Editor</option>
</select>
</div>
</form>
</div>
<!-- Footer with actions -->
<footer class="fd-dialog__footer fd-bar fd-bar--footer">
<div class="fd-bar__right">
<div class="fd-bar__element">
<button class="fd-button fd-button--emphasized" type="submit" form="user-form">Create User</button>
</div>
<div class="fd-bar__element">
<button class="fd-button fd-button--transparent">Cancel</button>
</div>
</div>
</footer>
</div>
</div>
Key points:
- Set explicit width on
fd-dialog__content(e.g., 500px) - Use
formelement with uniqueid - Link submit button to form with
formattribute - Place primary action (Create) on the right
- Place secondary action (Cancel) next to primary
- Close dialog on Cancel or X button click
- Close and refresh on successful submit
Pattern 7: Dashboard with Cards
A dashboard layout with multiple cards showing key metrics and information.
Components used:
fd-card- Information cardsfd-button- Card actions- CSS Grid - Layout
When to use:
- Application dashboards
- Analytics pages
- Overview screens
- KPI displays
Complete example:
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; padding: 1rem;">
<!-- Card 1: Metric -->
<div class="fd-card">
<div class="fd-card__header">
<div class="fd-card__header-text">
<h3 class="fd-card__title-area">Total Users</h3>
</div>
</div>
<div class="fd-card__content">
<div style="text-align: center; padding: 2rem 0;">
<div style="font-size: 3rem; font-weight: bold; color: var(--sapPositiveColor);">1,234</div>
<div style="color: var(--sapContent_LabelColor); margin-top: 0.5rem;">
<i class="sap-icon--arrow-top" style="color: var(--sapPositiveColor);"></i>
+12% from last month
</div>
</div>
</div>
</div>
<!-- Card 2: List -->
<div class="fd-card">
<div class="fd-card__header">
<div class="fd-card__header-text">
<h3 class="fd-card__title-area">Recent Activity</h3>
</div>
<div class="fd-card__header-toolbar">
<button class="fd-button fd-button--transparent fd-button--compact">View All</button>
</div>
</div>
<div class="fd-card__content" style="padding: 0;">
<ul class="fd-list">
<li class="fd-list__item">
<div class="fd-list__content">
<div class="fd-list__title">User registered</div>
<div class="fd-list__byline">2 minutes ago</div>
</div>
</li>
<li class="fd-list__item">
<div class="fd-list__content">
<div class="fd-list__title">Order completed</div>
<div class="fd-list__byline">15 minutes ago</div>
</div>
</li>
<li class="fd-list__item">
<div class="fd-list__content">
<div class="fd-list__title">Payment processed</div>
<div class="fd-list__byline">1 hour ago</div>
</div>
</li>
</ul>
</div>
</div>
<!-- Card 3: Status -->
<div class="fd-card">
<div class="fd-card__header">
<div class="fd-card__header-text">
<h3 class="fd-card__title-area">System Status</h3>
</div>
</div>
<div class="fd-card__content">
<div class="fd-form-item">
<label class="fd-form-label">API Server</label>
<span class="fd-object-status fd-object-status--positive">
<i class="sap-icon--status-positive"></i> Online
</span>
</div>
<div class="fd-form-item">
<label class="fd-form-label">Database</label>
<span class="fd-object-status fd-object-status--positive">
<i class="sap-icon--status-positive"></i> Connected
</span>
</div>
<div class="fd-form-item">
<label class="fd-form-label">Background Jobs</label>
<span class="fd-object-status fd-object-status--critical">
<i class="sap-icon--status-critical"></i> 2 Pending
</span>
</div>
</div>
</div>
</div>
Key points:
- Use CSS Grid with
auto-fitandminmaxfor responsive layout - Set minimum card width (e.g., 300px)
- Use
fd-card__header-toolbarfor card actions - Remove padding from
fd-card__contentwhen using lists - Use
fd-object-statusfor status indicators - Keep card content focused and concise
General Pattern Tips
Layout Best Practices
- Use CSS Grid for card/tile layouts
- Use Flexbox for single-axis layouts (toolbars, button groups)
- Set max-width on forms and content areas (e.g., 600-800px)
- Add spacing between components (1rem is a good default)
- Make layouts responsive with media queries or auto-fit grids
Component Composition
- Layer components logically - Container → Content → Actions
- Use semantic HTML - Forms use
<form>, lists use<ul>/<ol> - Group related actions - Keep primary and secondary actions together
- Maintain consistent spacing - Use
fd-form-itemfor vertical spacing
Accessibility
- Always include labels - Use
fd-form-labelwithforattribute - Link errors to fields - Use
aria-describedby - Set ARIA states -
aria-invalid,aria-required,aria-expanded - Provide alternative text -
aria-labelfor icon buttons - Manage focus - Set focus on first field in dialogs
State Management
- Show/hide components based on user interaction
- Update CSS classes for visual state (
is-selected,is-error) - Disable buttons during async operations
- Clear forms after successful submission
- Preserve form state when closing dialogs (ask for confirmation)
For more patterns and component details, consult:
- Component Guidance Skill (
component-guidance.md) - MCP Server tools (
get_component_html,get_component_guidance) - Fiori Design Guidelines (https://www.sap.com/design-system/fiori-design-web/)