Next.js

Next.js is a powerful React framework that supports both server-side rendering (SSR) and client-side rendering. While web components have traditionally faced challenges with SSR in Next.js, the DÁP Design System can be successfully integrated using client-side rendering strategies.

Next.js Compatibility
  • Next.js 13+ with App Router: Full support with client-side rendering
  • Next.js 14+ with React 18: Recommended for optimal performance
  • Next.js 15+ with React 19: Native web component support (experimental)
SSR Considerations

Web components require browser APIs that aren't available during server-side rendering. The recommended approach is to use client-side rendering with the 'use client' directive for components that use the DÁP Design System.

Installation

Install the DÁP Design System package:

npm install dap-design-system
Setup with App Router

The App Router (Next.js 13+) is the recommended approach for new projects. Here's how to set up the DÁP Design System:

1. Create a Client Component Wrapper

Create a client-side component to load the design system components:

'use client'

import { ReactNode, useEffect } from 'react'

export default function ClientApplication({
  children,
}: {
  children: ReactNode
}) {
  useEffect(() => {
    async function getComponents() {
      await import('dap-design-system/dist/dds')
    }

    getComponents()
  }, [])

  return children
}
2. Configure Root Layout

Update your root layout to include the design system styles, fonts, and client wrapper:

import localFont from 'next/font/local'
import { ReactNode, Suspense } from 'react'
import 'dap-design-system/dist/light.theme.css'

import ClientApplication from '@/app/clientApplication'

const inter = localFont({
  src: '[path to your font, check the Typography page]',
  display: 'swap',
  weight: '500 700',
  style: 'normal',
  declarations: [
    { prop: 'font-feature-settings', value: "'liga' 1,'calt' 1,'ss02' 1" },
    { prop: 'font-variation-settings', value: "'slnt' 0" },
    { prop: 'font-optical-sizing', value: 'auto' },
  ],
})

export default async function RootLayout({
  children,
}: Readonly<{
  children: ReactNode
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ClientApplication>
          <Suspense fallback={<Loading />}>
            <main className="main" id="root">
              {children}
            </main>
          </Suspense>
        </ClientApplication>
      </body>
    </html>
  )
}

3. Using Components

After setup, you can use DÁP Design System components in your Next.js project. Remember to use the 'use client' directive in components that use the design system.

'use client'

import { useState } from 'react'

export default function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  })

  const handleInputChange = (e: CustomEvent, field: string) => {
    setFormData(prev => ({
      ...prev,
      [field]: e.detail?.value || ''
    }))
  }

  const handleSubmit = (e: CustomEvent) => {
    e.preventDefault()
    console.log('Form submitted:', formData)
  }

  return (
    <div className="max-w-md mx-auto p-6">
      <dap-ds-typography variant="h2">
        Contact Us
      </dap-ds-typography>
      
      <form ondds-submit={handleSubmit} className="space-y-4">
        <dap-ds-input
          label="Name"
          placeholder="Your full name"
          value={formData.name}
          ondds-change={(e) => handleInputChange(e, 'name')}
          required
        />
        
        <dap-ds-input
          label="Email"
          type="email"
          placeholder="your.email@example.com"
          value={formData.email}
          ondds-change={(e) => handleInputChange(e, 'email')}
          required
        />
        
        <dap-ds-textarea
          label="Message"
          placeholder="Tell us about your project..."
          value={formData.message}
          rows={4}
          ondds-change={(e) => handleInputChange(e, 'message')}
          required
        />
        
        <dap-ds-button type="submit" variant="primary" className="w-full">
          Send Message
        </dap-ds-button>
      </form>
    </div>
  )
}
TypeScript Support

For full TypeScript support in Next.js, add the type definitions to your project:

Adding Type Definitions

Create or update your global.d.ts file in your project root:

declare namespace JSX {
  interface IntrinsicElements {
    'dap-ds-accordion': import('dap-design-system/dist/react-types').DapDSAccordionType
    'dap-ds-accordion-group': import('dap-design-system/dist/react-types').DapDSAccordionGroupType
    'dap-ds-avatar': import('dap-design-system/dist/react-types').DapDSAvatarType
    'dap-ds-avatar-group': import('dap-design-system/dist/react-types').DapDSAvatarGroupType
    'dap-ds-badge': import('dap-design-system/dist/react-types').DapDSBadgeType
    'dap-ds-banner': import('dap-design-system/dist/react-types').DapDSBannerType
    'dap-ds-breadcrumb': import('dap-design-system/dist/react-types').DapDSBreadcrumbType
    'dap-ds-breadcrumb-item': import('dap-design-system/dist/react-types').DapDSBreadcrumbItemType
    'dap-ds-button': import('dap-design-system/dist/react-types').DapDSButtonType
    'dap-ds-calendar': import('dap-design-system/dist/react-types').DapDSCalendarType
    'dap-ds-calendar-cell': import('dap-design-system/dist/react-types').DapDSCalendarCellType
    'dap-ds-callout': import('dap-design-system/dist/react-types').DapDSCalloutType
    'dap-ds-card': import('dap-design-system/dist/react-types').DapDSCardType
    'dap-ds-card-actions': import('dap-design-system/dist/react-types').DapDSCardActionsType
    'dap-ds-card-content': import('dap-design-system/dist/react-types').DapDSCardContentType
    'dap-ds-card-image': import('dap-design-system/dist/react-types').DapDSCardImageType
    'dap-ds-card-subtitle': import('dap-design-system/dist/react-types').DapDSCardSubtitleType
    'dap-ds-card-title': import('dap-design-system/dist/react-types').DapDSCardTitleType
    'dap-ds-checkbox': import('dap-design-system/dist/react-types').DapDSCheckboxType
    'dap-ds-combobox': import('dap-design-system/dist/react-types').DapDSComboboxType
    'dap-ds-command': import('dap-design-system/dist/react-types').DapDSCommandType
    'dap-ds-command-group': import('dap-design-system/dist/react-types').DapDSCommandGroupType
    'dap-ds-command-item': import('dap-design-system/dist/react-types').DapDSCommandItemType
    'dap-ds-content-switcher': import('dap-design-system/dist/react-types').DapDSContentSwitcherType
    'dap-ds-content-switcher-item': import('dap-design-system/dist/react-types').DapDSContentSwitcherItemType
    'dap-ds-copybox-input': import('dap-design-system/dist/react-types').DapDSCopyBoxInputType
    'dap-ds-datatable': import('dap-design-system/dist/react-types').DapDSDataTableType
    'dap-ds-datepicker': import('dap-design-system/dist/react-types').DapDSDatePickerType
    'dap-ds-divider': import('dap-design-system/dist/react-types').DapDSDividerType
    'dap-ds-feedback': import('dap-design-system/dist/react-types').DapDSFeedbackType
    'dap-ds-file-input': import('dap-design-system/dist/react-types').DapDSFileInputType
    'dap-ds-file-input-list': import('dap-design-system/dist/react-types').DapDSFileInputListType
    'dap-ds-file-input-list-item': import('dap-design-system/dist/react-types').DapDSFileInputListItemType
    'dap-ds-form-label': import('dap-design-system/dist/react-types').DapDSFormLabelType
    'dap-ds-icon': import('dap-design-system/dist/react-types').DapDSIconType
    'dap-ds-icon-button': import('dap-design-system/dist/react-types').DapDSIconButtonType
    'dap-ds-input': import('dap-design-system/dist/react-types').DapDSInputType
    'dap-ds-input-group': import('dap-design-system/dist/react-types').DapDSInputGroupType
    'dap-ds-label': import('dap-design-system/dist/react-types').DapDSLabelType
    'dap-ds-link': import('dap-design-system/dist/react-types').DapDSLinkType
    'dap-ds-list-item': import('dap-design-system/dist/react-types').DapDSListItemType
    'dap-ds-modal': import('dap-design-system/dist/react-types').DapDSModalType
    'dap-ds-notification-badge': import('dap-design-system/dist/react-types').DapDSNotificationBadgeType
    'dap-ds-number-input': import('dap-design-system/dist/react-types').DapDSNumberInputType
    'dap-ds-official-website-banner': import('dap-design-system/dist/react-types').DapDSOfficialWebsiteBannerType
    'dap-ds-option-item': import('dap-design-system/dist/react-types').DapDSOptionItemType
    'dap-ds-option-list': import('dap-design-system/dist/react-types').DapDSOptionListType
    'dap-ds-overlay': import('dap-design-system/dist/react-types').DapDSOverlayType
    'dap-ds-pager': import('dap-design-system/dist/react-types').DapDSPagerType
    'dap-ds-password-input': import('dap-design-system/dist/react-types').DapDSPasswordInputType
    'dap-ds-popup': import('dap-design-system/dist/react-types').DapDSPopupType
    'dap-ds-radio-button': import('dap-design-system/dist/react-types').DapDSRadioButtonType
    'dap-ds-radio-group': import('dap-design-system/dist/react-types').DapDSRadioGroupType
    'dap-ds-rating': import('dap-design-system/dist/react-types').DapDSRatingType
    'dap-ds-scroll-area': import('dap-design-system/dist/react-types').DapDSScrollAreaType
    'dap-ds-search': import('dap-design-system/dist/react-types').DapDSSearchType
    'dap-ds-select': import('dap-design-system/dist/react-types').DapDSSelectType
    'dap-ds-sidenav': import('dap-design-system/dist/react-types').DapDSSideNavType
    'dap-ds-sidenav-group': import('dap-design-system/dist/react-types').DapDSSideNavGroupType
    'dap-ds-sidenav-item': import('dap-design-system/dist/react-types').DapDSSideNavItemType
    'dap-ds-skip-link': import('dap-design-system/dist/react-types').DapDSSkipLinkType
    'dap-ds-snackbar': import('dap-design-system/dist/react-types').DapDSSnackbarType
    'dap-ds-snackbar-message': import('dap-design-system/dist/react-types').DapDSSnackbarMessageType
    'dap-ds-spinner': import('dap-design-system/dist/react-types').DapDSSpinnerType
    'dap-ds-stack': import('dap-design-system/dist/react-types').DapDSStackType
    'dap-ds-switch': import('dap-design-system/dist/react-types').DapDSSwitchType
    'dap-ds-tab': import('dap-design-system/dist/react-types').DapDSTabType
    'dap-ds-tab-group': import('dap-design-system/dist/react-types').DapDSTabGroupType
    'dap-ds-table': import('dap-design-system/dist/react-types').DapDSTableType
    'dap-ds-table-cell': import('dap-design-system/dist/react-types').DapDSTableCellType
    'dap-ds-table-header': import('dap-design-system/dist/react-types').DapDSTableHeaderType
    'dap-ds-table-row': import('dap-design-system/dist/react-types').DapDSTableRowType
    'dap-ds-textarea': import('dap-design-system/dist/react-types').DapDSTextareaType
    'dap-ds-timeline': import('dap-design-system/dist/react-types').DapDSTimelineType
    'dap-ds-timeline-item': import('dap-design-system/dist/react-types').DapDSTimelineItemType
    'dap-ds-toc': import('dap-design-system/dist/react-types').DapDSTOCType
    'dap-ds-toggle-button': import('dap-design-system/dist/react-types').DapDSToggleButtonType
    'dap-ds-tooltip': import('dap-design-system/dist/react-types').DapDSTooltipType
    'dap-ds-tray': import('dap-design-system/dist/react-types').DapDSTrayType
    'dap-ds-typography': import('dap-design-system/dist/react-types').DapDSTypographyType
  }
}

declare module 'dap-design-system/dist/dds.js'
TypeScript Configuration

Update your tsconfig.json to include the type definitions:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"]
    }
  },
  "include": [
    "next-env.d.ts",
    "global.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts"
  ],
  "exclude": ["node_modules"]
}
Next.js 15 with React 19

Next.js 15 with React 19 provides experimental native web component support. Here's how to leverage it:

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    // Enable React 19 features
    reactCompiler: true,
  },
  transpilePackages: ['dap-design-system'],
}

module.exports = nextConfig

With React 19, you can use web components more naturally:

'use client'

import { useState } from 'react'
import 'dap-design-system/dist/dds.js'
import 'dap-design-system/dist/light.theme.css'

export default function React19Example() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <dap-ds-typography variant="h3">
        React 19 + Next.js 15 Integration
      </dap-ds-typography>
      
      <dap-ds-card>
        <dap-ds-card-content>
          <p>Count: {count}</p>
          <dap-ds-button 
            ondds-click={() => setCount(c => c + 1)}
            variant="primary"
          >
            Increment
          </dap-ds-button>
        </dap-ds-card-content>
      </dap-ds-card>
    </div>
  )
}
Best Practices Theme Management
'use client'

import { useEffect, useState } from 'react'

export default function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<'light' | 'dark'>('light')

  useEffect(() => {
    // Load theme-specific CSS
    import(`dap-design-system/dist/${theme}.theme.css`)
  }, [theme])

  useEffect(() => {
    // Set theme attribute on document
    document.documentElement.setAttribute('data-theme', theme)
  }, [theme])

  return (
    <div data-theme={theme}>
      {children}
      
      <dap-ds-button 
        variant="ghost"
        ondds-click={() => setTheme(t => t === 'light' ? 'dark' : 'light')}
      >
        Toggle Theme
      </dap-ds-button>
    </div>
  )
}
Troubleshooting Common Issues

Hydration Mismatch: Web components render differently on server vs client

// Solution: Use dynamic imports with ssr: false
const ClientOnlyComponent = dynamic(() => import('./MyComponent'), {
  ssr: false
})

TypeScript Errors: Missing type definitions

# Ensure global.d.ts is included in your tsconfig.json
npm run type-check

Styling Issues: CSS not loading properly

// Make sure to import theme CSS in your layout
import 'dap-design-system/dist/light.theme.css'
Development vs Production

Ensure your build process handles web components correctly:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "type-check": "tsc --noEmit"
  }
}