Skip to content

CopyMarkup

Introduction

The CopyMarkup component allows users to dynamically duplicate form fields or content blocks, providing add/remove functionality, customizable button styles, alignment, spacing, and limits. It is ideal for scenarios like adding multiple emails, addresses, skills, or any repeatable input in forms.

Import

tsx
import { CopyMarkup } from '@odyssee/components';

LiveCodeEditor Examples

Basic CopyMarkup

Code Éditable
Résultat

With Initial Items

Code Éditable
Résultat

Button Variants

Code Éditable
Résultat

Button Position

Code Éditable
Résultat

Spacing Options

Code Éditable
Résultat

Different Field Types

Code Éditable
Résultat

States: Remove Button, Disabled, Limit Reached

Code Éditable
Résultat

Props Table

PropTypeDefaultDescription
templatePulse.JSX.ElementrequiredThe form field or content to duplicate.
buttonTextstring"Add Item"Text for the add button.
buttonIconPulse.JSX.ElementCustom icon for the add button.
buttonVariant"outline" | "solid" | "ghost" | "danger""outline"Style variant for the add button.
buttonPosition"left" | "center" | "right""right"Alignment of the add button.
limitnumber10Maximum number of duplicated items.
initialCountnumber0Number of items to render initially.
showRemoveButtonbooleantrueWhether to show a remove button for each item.
removeButtonTextstringAccessible label for the remove button.
spacing"sm" | "md" | "lg" | "xl""md"Vertical spacing between items.
onChange(count: number) => voidCallback fired when the number of items changes.
onAdd(count: number) => voidCallback fired when an item is added.
onRemove(count: number) => voidCallback fired when an item is removed.
buttonClassNamestringAdditional CSS classes for the add button.
wrapperClassNamestringAdditional CSS classes for the items wrapper.
disabledbooleanfalseDisables the add button and all remove buttons.
classNamestringAdditional CSS classes for the root element.
idstringauto-genUnique ID for the CopyMarkup container.
...restanyOther props are spread to the root element.

Implementation Notes

  • Fully reactive: uses Pulse signals for item count and rendering.
  • Supports any JSX element as a template (Input, Select, Textarea, custom blocks).
  • Add/remove buttons are styled and accessible; limit is enforced.
  • Button alignment and spacing are customizable.
  • Callbacks (onChange, onAdd, onRemove) allow integration with form logic.
  • Remove button can be hidden for simple duplication scenarios.
  • Initial count allows pre-populating items.

Accessibility

  • Add and remove buttons use aria-label and accessible text.
  • Remove button is visually hidden when not needed.
  • Keyboard navigation is supported for all interactive elements.
  • Limit indicator is announced via text when reached.
  • Works with any accessible form field as a template.

Best Practices

  • Use limit to prevent excessive duplication and maintain UX.
  • Provide clear buttonText and accessible removeButtonText.
  • Use onChange to synchronize with form state or validation.
  • Group related fields with appropriate spacing for clarity.
  • Hide remove button for simple repeatable fields where removal is not needed.
  • Use initialCount to pre-populate fields for common use cases.

Released under the MIT License.