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.Element—Custom 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.
removeButtonTextstring—Accessible label for the remove button.
spacing"sm" | "md" | "lg" | "xl""md"Vertical spacing between items.
onChange(count: number) => void—Callback fired when the number of items changes.
onAdd(count: number) => void—Callback fired when an item is added.
onRemove(count: number) => void—Callback fired when an item is removed.
buttonClassNamestring—Additional CSS classes for the add button.
wrapperClassNamestring—Additional CSS classes for the items wrapper.
disabledbooleanfalseDisables the add button and all remove buttons.
classNamestring—Additional CSS classes for the root element.
idstringauto-genUnique ID for the CopyMarkup container.
...restany—Other 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.