Skip to Content
GuidesBest Practices

Best Practices

Follow these guidelines to create high-quality templates that pass review, sell well, and make trainers happy.

Performance

Lazy loading

Use lazy loading for images below the fold:

<img src={imageSrc} alt={altText} loading="lazy" width={800} height={600} />

Optimised images

  • Use appropriate image formats (WebP preferred, PNG for transparency)
  • Serve responsive sizes with srcset where possible
  • Set explicit width and height to prevent layout shift

Minimal JavaScript

Keep client-side JavaScript lightweight. Templates should feel fast:

  • Avoid heavy animation libraries — use CSS animations and transitions
  • Don’t import large utility libraries for one function
  • Use dynamic imports for components not visible on initial load

CSS performance

  • Avoid deeply nested selectors
  • Minimise use of * selectors
  • Use will-change sparingly — only on elements that actually animate
  • Prefer transform and opacity for animations (they’re GPU-accelerated)

Accessibility

Semantic HTML

Use HTML elements for their intended purpose:

// ✅ Correct <nav>...</nav> <main>...</main> <header>...</header> <footer>...</footer> <button onClick={handleClick}>Click me</button> // ❌ Incorrect <div className="nav">...</div> <div className="main">...</div> <div onClick={handleClick}>Click me</div>

ARIA attributes

Add ARIA attributes where semantic HTML isn’t sufficient:

<button aria-label={t('toggleMenu')} aria-expanded={menuOpen} onClick={() => setMenuOpen(!menuOpen)} > <HamburgerIcon /> </button> <nav aria-label="Main navigation"> {/* links */} </nav> <div role="alert" aria-live="polite"> {errorMessage} </div>

Keyboard navigation

Ensure all interactive elements are keyboard-accessible:

  • All clickable elements should be <button> or <a> elements
  • Focus order should follow visual order
  • Modals and mobile menus should trap focus
  • Escape should close modals and overlays
  • Visible focus indicators on all interactive elements
.button:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

Colour contrast

Ensure text meets WCAG AA contrast ratios:

  • Normal text: minimum 4.5:1 contrast ratio
  • Large text (18px+ bold, 24px+ regular): minimum 3:1 contrast ratio
  • Check contrast in both light and dark modes

Code quality

Clean CSS

  • Use consistent naming conventions (camelCase for CSS Modules)
  • Group related properties logically
  • Add comments only for non-obvious design decisions

No inline styles

Avoid inline styles — they can’t be themed and make RTL overrides difficult:

// ❌ Avoid <div style={{ marginLeft: '1rem', color: '#333' }}> // ✅ Prefer <div className={styles.container}>

Exception: truly dynamic values like style={"{{ width: percentage + '%' }}"} are acceptable.

Component organisation

  • One component per file
  • Co-locate CSS modules with their components
  • Keep components focused — extract sub-components when complexity grows
  • Name files consistently: ComponentName.tsx + ComponentName.module.css

What reviewers look for

During the review process, Gymlium admins evaluate:

AreaWhat they check
FunctionalityAll pages render, navigation works, no console errors
RTL supportLayout mirrors correctly in Arabic, no overlapping elements
Dark/light modeBoth modes look polished, no invisible text or missing borders
ResponsivenessMobile menu works, layouts adapt, no horizontal scroll
PerformancePages load quickly, no layout shift, smooth animations
AccessibilityKeyboard navigation, semantic HTML, ARIA labels
Code qualityClean CSS, no inline styles, correct export patterns
TranslationsNo hardcoded text — all user-facing strings use t()
AssetsQuality thumbnail, reasonable file sizes

Templates that check all these boxes typically pass review on the first submission. Addressing these from the start saves you revision cycles.

Last updated on