SKILL.md
UI Consistency Guidelines
Ensures consistent, accessible UI across Waldur HomePort.
Quick Reference (Critical Rules)
Null/Empty Values
// ALWAYS use renderFieldOrDash - never || 'N/A' or || ''
import { renderFieldOrDash } from '@/table/utils';
{renderFieldOrDash(value)}
Disabled Buttons
// ALWAYS provide tooltip explaining WHY disabled
<Tip label={disabled ? translate('Resource must be in OK state') : null}>
<Button disabled={disabled}>Action</Button>
</Tip>
Empty States
// ALWAYS use NoResult with actionable CTA
<NoResult
title={translate('No projects yet')}
message={translate('Create your first project.')}
actions={<CreateButton />}
/>
Disabled Styling
// Use solid color tokens - NEVER opacity
className={isDisabled ? 'text-muted' : ''} // correct
className={isDisabled ? 'opacity-50' : ''} // wrong
Decision Trees
Hide vs Disable Button?
- User PERMANENTLY lacks permission → HIDE
- Temporary/fixable condition → DISABLE + tooltip
Which Empty State?
- Active filters, no results → "No results match your filters" + Clear filters button
- First-time use → Encouraging message + Create CTA
- Search query, no match → "Your search '{query}' did not match any {items}"
Complete Guidelines
For full patterns, examples, and anti-patterns: [docs/ui-consistency-guidelines.md](../../../docs/ui-consistency-guidelines.md)
Sections include:
- Empty states and NoResult component
- Button visibility (hide vs disable matrix)
- Loading states and error handling
- Tables and filter behavior
- Dialogs and confirmations
- Notifications
- Status indicators
- Tooltips
- Accessibility
- Responsive behavior
Pre-Commit Checklist
Before completing UI work, verify:
Key Imports
import { NoResult } from '@/navigation/header/search/NoResult';
import { renderFieldOrDash } from '@/table/utils';
import { Tip } from '@/core/Tooltip';
import { hasPermission } from '@/permissions/hasPermission';
import { StateIndicator } from '@/core/StateIndicator';
import { LoadingErred } from '@/core/LoadingErred';