Implementing Syncfusion React Inputs Uploader The Syncfusion React UploaderComponent provides a rich file upload control with async upload, drag-and-drop, chunk upload with pause/resume/cancel, validation, templates, form integration, and accessibility support. Navigation Guide 🛑 Agentic use: Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation). Getting Started 📄 Read: references/getting-started.md - Installing 🛑 STOP — Do not install packages autonomously. Ask the user to run: . Verify with - License registration - Basic usage…

+ args.value;\n}\n\n\u003cSliderComponent tooltipChange={tooltipChangeHandler.bind(this) as any} />\n```\n\n## Next Steps\n\n1. Configure appropriate tooltip visibility for your use case\n2. Add ticks if showing a scale helps users\n3. Consider formatting for special value types (currency, percentage)\n4. Review [styling.md](styling.md) to customize appearance\n5. Test keyboard navigation in [accessibility.md](accessibility.md)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12091,"content_sha256":"3c1f8b19fe64877a5962e0c3e86adad06c23ae8e574de2dbdea57e5370663353"},{"filename":"references/range-slider-types-and-orientation.md","content":"# Types and Orientation\n\n## Table of Contents\n- [Slider Types Overview](#slider-types-overview)\n- [Default Type](#default-type)\n- [MinRange Type](#minrange-type)\n- [Range Type](#range-type)\n- [Type Comparison](#type-comparison)\n- [Orientation](#orientation)\n- [Horizontal Slider](#horizontal-slider)\n- [Vertical Slider](#vertical-slider)\n- [Combining Types and Orientation](#combining-types-and-orientation)\n\n## Slider Types Overview\n\nThe RangeSlider component supports three types, each with different handle counts and fill behaviors:\n\n| Type | Handles | Fill | Use Case |\n|------|---------|------|----------|\n| **Default** | 1 | No | Simple single value selection |\n| **MinRange** | 1 | Yes | Progress/level indicator with visual fill |\n| **Range** | 2 | Yes | Min/max range selection |\n\n## Default Type\n\nThe Default type provides a simple single-handle slider for selecting one value within a range.\n\n### Characteristics\n\n- **Single handle:** One draggable point on the track\n- **No fill:** No colored shadow or fill area\n- **Use:** Simple numeric selection (age, quantity, rating)\n\n### Basic Example\n\n```tsx\nimport React, { useState } from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction DefaultSliderExample() {\n const [value, setValue] = useState(30);\n\n return (\n \u003cdiv>\n \u003ch3>Age Selector\u003c/h3>\n \u003cp>Selected Age: {value}\u003c/p>\n \u003cSliderComponent\n id=\"age-slider\"\n type=\"Default\"\n value={value}\n change={(e) => setValue(e.value as number)}\n min={18}\n max={80}\n step={1}\n />\n \u003c/div>\n );\n}\n\nexport default DefaultSliderExample;\n```\n\n### Common Patterns\n\n**Quantity Selector:**\n```tsx\n\u003cSliderComponent\n id=\"quantity\"\n type=\"Default\"\n value={1}\n min={1}\n max={100}\n step={1}\n tooltip={{ isVisible: true }}\n/>\n```\n\n**Volume Control:**\n```tsx\n\u003cSliderComponent\n id=\"volume\"\n type=\"Default\"\n value={50}\n min={0}\n max={100}\n step={5}\n tooltip={{\n isVisible: true,\n placement: 'Before'\n }}\n/>\n```\n\n## MinRange Type\n\nThe MinRange type uses a single handle with a colored fill from the start (min) value to the current handle position.\n\n### Characteristics\n\n- **Single handle:** One draggable point\n- **Fill from min:** Colored shadow/fill from minimum to handle position\n- **Visual feedback:** Shows progress or level clearly\n- **Use:** Progress bars, level indicators, completion percentage\n\n### Basic Example\n\n```tsx\nimport React, { useState } from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction MinRangeExample() {\n const [progress, setProgress] = useState(40);\n\n return (\n \u003cdiv>\n \u003ch3>Download Progress\u003c/h3>\n \u003cp>Progress: {progress}%\u003c/p>\n \u003cSliderComponent\n id=\"progress-slider\"\n type=\"MinRange\"\n value={progress}\n change={(e) => setProgress(e.value as number)}\n min={0}\n max={100}\n step={1}\n tooltip={{ isVisible: true }}\n />\n \u003c/div>\n );\n}\n\nexport default MinRangeExample;\n```\n\n### Visual Difference\n\n```\nDefault Slider:\n|●----- No fill --------|\n\nMinRange Slider:\n|■■■●----- Fill to handle --------|\n ↑ colored fill from min\n\nRange Slider:\n|---○■■■■■■●-----| Two handles, fill between\n ↑ ↑\n```\n\n### Common Patterns\n\n**Task Completion Level:**\n```tsx\n\u003cSliderComponent\n id=\"completion\"\n type=\"MinRange\"\n value={75}\n min={0}\n max={100}\n step={5}\n tooltip={{\n isVisible: true,\n format: 'P0' // Display as percentage\n }}\n/>\n```\n\n**Brightness Level:**\n```tsx\n\u003cSliderComponent\n id=\"brightness\"\n type=\"MinRange\"\n value={70}\n min={0}\n max={100}\n step={10}\n/>\n```\n\n**Storage Usage:**\n```tsx\n\u003cSliderComponent\n id=\"storage\"\n type=\"MinRange\"\n value={65} // 65GB used\n min={0}\n max={256}\n step={5}\n tooltip={{ isVisible: true }}\n/>\n```\n\n## Range Type\n\nThe Range type provides two handles for selecting a minimum and maximum value range.\n\n### Characteristics\n\n- **Two handles:** Start and end draggable points\n- **Fill between handles:** Colored fill between the two selected values\n- **Use:** Price ranges, date ranges, score ranges, any min-max selection\n\n### Basic Example\n\n```tsx\nimport React, { useState } from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction RangeSliderExample() {\n const [priceRange, setPriceRange] = useState([100, 500]);\n\n return (\n \u003cdiv>\n \u003ch3>Price Range Filter\u003c/h3>\n \u003cp>Price: ${priceRange[0]} - ${priceRange[1]}\u003c/p>\n \u003cSliderComponent\n id=\"price-range\"\n type=\"Range\"\n value={priceRange}\n change={(e) => setPriceRange(e.value as number[])}\n min={0}\n max={1000}\n step={10}\n tooltip={{ isVisible: true }}\n />\n \u003c/div>\n );\n}\n\nexport default RangeSliderExample;\n```\n\n### Handle Behavior\n\n**First Handle (Start):** Restricted by max value of first handle and min value of second handle\n\n**Second Handle (End):** Restricted by min value of second handle and max value of first handle\n\n**Example:**\n```tsx\n// If first handle at 30, second handle can't go below 30\n// If second handle at 70, first handle can't go above 70\n\u003cSliderComponent\n id=\"range\"\n type=\"Range\"\n value={[30, 70]}\n min={0}\n max={100}\n/>\n```\n\n### Common Patterns\n\n**Age Range Filter:**\n```tsx\n\u003cSliderComponent\n id=\"age-range\"\n type=\"Range\"\n value={[18, 65]}\n min={0}\n max={100}\n step={5}\n tooltip={{ isVisible: true }}\n/>\n```\n\n**Date Range Selector:**\n```tsx\n// Note: For actual dates, use DateRangePicker component\n// For numeric day range:\n\u003cSliderComponent\n id=\"date-range\"\n type=\"Range\"\n value={[1, 30]}\n min={1}\n max={31}\n step={1}\n tooltip={{ isVisible: true }}\n/>\n```\n\n**Score Range Filter:**\n```tsx\n\u003cSliderComponent\n id=\"score-range\"\n type=\"Range\"\n value={[3, 5]}\n min={1}\n max={5}\n step={0.5}\n tooltip={{ isVisible: true }}\n/>\n```\n\n## Type Comparison\n\n### Full Comparison Table\n\n```tsx\n// Default - Single value, no fill\n\u003cSliderComponent\n id=\"default\"\n type=\"Default\"\n value={50}\n tooltip={{ isVisible: true }}\n/>\n\n// MinRange - Single value with fill from min\n\u003cSliderComponent\n id=\"minrange\"\n type=\"MinRange\"\n value={50}\n tooltip={{ isVisible: true }}\n/>\n\n// Range - Two values with fill between\n\u003cSliderComponent\n id=\"range\"\n type=\"Range\"\n value={[30, 70]}\n tooltip={{ isVisible: true }}\n/>\n```\n\n### When to Use Each Type\n\n**Use Default when:**\n- Selecting a single, independent value\n- No need to show progress or level\n- Simple input (age, quantity, rating)\n- UI space is limited to single handle\n\n**Use MinRange when:**\n- Need visual progress/level indicator\n- Single value but with context (progress %, completion)\n- Want fill from minimum to selection\n- Similar use case to progress bar\n\n**Use Range when:**\n- Selecting min and max values\n- Filtering by range (prices, dates, scores)\n- Need two correlated values\n- Show range as interval on track\n\n## Orientation\n\n### Horizontal Slider\n\nDefault orientation - slider displays left-to-right.\n\n```tsx\n\u003cSliderComponent\n id=\"horizontal\"\n value={50}\n orientation=\"Horizontal\"\n // or omit, as Horizontal is default\n/>\n```\n\n**Good for:**\n- Standard layouts\n- Desktop/tablet interfaces\n- Wide containers\n\n### Vertical Slider\n\nDisplay slider top-to-bottom for space-constrained layouts.\n\n```tsx\n\u003cdiv style={{ height: '400px', width: '100px' }}>\n \u003cSliderComponent\n id=\"vertical\"\n value={50}\n orientation=\"Vertical\"\n />\n\u003c/div>\n```\n\n**Important:** Wrap vertical slider in a container with defined `height`. Otherwise, slider won't have space to render.\n\n### Vertical Slider Example\n\n```tsx\nimport React, { useState } from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction VerticalSliderExample() {\n const [volume, setVolume] = useState(50);\n\n return (\n \u003cdiv style={{ display: 'flex', gap: '40px', padding: '20px' }}>\n {/* Horizontal */}\n \u003cdiv>\n \u003ch3>Horizontal\u003c/h3>\n \u003cSliderComponent\n id=\"horizontal\"\n value={volume}\n change={(e) => setVolume(e.value as number)}\n />\n \u003c/div>\n\n {/* Vertical */}\n \u003cdiv style={{ height: '300px' }}>\n \u003ch3>Vertical\u003c/h3>\n \u003cSliderComponent\n id=\"vertical\"\n value={volume}\n change={(e) => setVolume(e.value as number)}\n orientation=\"Vertical\"\n />\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default VerticalSliderExample;\n```\n\n### Keyboard Behavior\n\n**Horizontal:**\n- Right Arrow: Increase value\n- Left Arrow: Decrease value\n\n**Vertical:**\n- Up Arrow: Increase value\n- Down Arrow: Decrease value\n- Home/End: Move to min/max\n\n## Combining Types and Orientation\n\n### All Combinations Example\n\n```tsx\nimport React from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction AllCombinations() {\n return (\n \u003cdiv style={{ padding: '20px' }}>\n \u003cdiv style={{ marginBottom: '30px' }}>\n \u003ch3>Horizontal Sliders\u003c/h3>\n \u003cp>Default\u003c/p>\n \u003cSliderComponent id=\"h-default\" type=\"Default\" value={40} />\n \n \u003cp>MinRange\u003c/p>\n \u003cSliderComponent id=\"h-minrange\" type=\"MinRange\" value={40} />\n \n \u003cp>Range\u003c/p>\n \u003cSliderComponent id=\"h-range\" type=\"Range\" value={[30, 70]} />\n \u003c/div>\n\n \u003cdiv style={{ display: 'flex', gap: '50px' }}>\n \u003cdiv style={{ height: '300px' }}>\n \u003ch3>Vertical Default\u003c/h3>\n \u003cSliderComponent\n id=\"v-default\"\n type=\"Default\"\n value={40}\n orientation=\"Vertical\"\n />\n \u003c/div>\n\n \u003cdiv style={{ height: '300px' }}>\n \u003ch3>Vertical MinRange\u003c/h3>\n \u003cSliderComponent\n id=\"v-minrange\"\n type=\"MinRange\"\n value={40}\n orientation=\"Vertical\"\n />\n \u003c/div>\n\n \u003cdiv style={{ height: '300px' }}>\n \u003ch3>Vertical Range\u003c/h3>\n \u003cSliderComponent\n id=\"v-range\"\n type=\"Range\"\n value={[30, 70]}\n orientation=\"Vertical\"\n />\n \u003c/div>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default AllCombinations;\n```\n\n### Recommendations\n\n- **Desktop:** Use horizontal orientation (standard, familiar)\n- **Mobile:** Consider vertical for space efficiency\n- **Type selection:** Choose based on value count (1 vs 2) and visual feedback needs\n- **Space:** Vertical sliders need at least 200px height to display properly\n\n## Common Pitfalls\n\n### Forgetting Container Height for Vertical\n\n**❌ This won't work:**\n```tsx\n\u003cSliderComponent orientation=\"Vertical\" />\n```\n\n**✅ Do this instead:**\n```tsx\n\u003cdiv style={{ height: '300px' }}>\n \u003cSliderComponent orientation=\"Vertical\" />\n\u003c/div>\n```\n\n### Range Type with Single Value\n\n**❌ Incorrect:**\n```tsx\n\u003cSliderComponent type=\"Range\" value={50} /> // Should be [50, 50]\n```\n\n**✅ Correct:**\n```tsx\n\u003cSliderComponent type=\"Range\" value={[30, 70]} />\n```\n\n### Confusing MinRange with Range\n\n**MinRange = progress:** Shows fill from min to handle\n**Range = interval:** Shows fill between two handles\n\n## Next Steps\n\n1. Choose appropriate type for your use case\n2. Add tooltips from [tooltips-and-ticks.md](tooltips-and-ticks.md)\n3. Configure limits if needed from [formatting-and-limits.md](formatting-and-limits.md)\n4. Style with [styling.md](styling.md)\n5. Test accessibility with [accessibility.md](accessibility.md)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11366,"content_sha256":"781bcad0eafb62b751bb9c5a7c05d4285a9c0c6b62ccf692cf2723b599b7bb89"},{"filename":"references/rating-accessibility.md","content":"# Accessibility in React Rating Component\n\n## Table of Contents\n- [Compliance Summary](#compliance-summary)\n- [WAI-ARIA Attributes](#wai-aria-attributes)\n- [Keyboard Navigation](#keyboard-navigation)\n- [RTL Support](#rtl-support)\n- [Ensuring Accessibility](#ensuring-accessibility)\n\n---\n\n## Compliance Summary\n\nThe Syncfusion React Rating component meets the following accessibility standards:\n\n| Criteria | Status |\n|----------|--------|\n| WCAG 2.2 | ✅ Full support |\n| Section 508 | ✅ Full support |\n| ADA | ✅ Full support |\n| Screen Reader Support | ✅ Full support |\n| Right-To-Left (RTL) | ✅ Full support |\n| Color Contrast | ✅ Full support |\n| Mobile Device Support | ✅ Full support |\n| Keyboard Navigation | ✅ Full support |\n| Accessibility Checker Validation | ✅ Passed |\n| Axe-core Validation | ✅ Passed |\n\n---\n\n## WAI-ARIA Attributes\n\nThe Rating component follows the [WAI-ARIA slider pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slider/).\n\n| Attribute | Purpose |\n|-----------|---------|\n| `role=\"slider\"` | Identifies the input as a range slider |\n| `role=\"button\"` | Applied to the reset button |\n| `aria-label` | Provides an accessible name for the rating |\n| `aria-valuemin` | Defines the minimum rating value |\n| `aria-valuemax` | Defines the maximum rating value |\n| `aria-valuenow` | Reflects the current selected value |\n| `aria-hidden` | Applied to the reset button when not interactive |\n\nThese are applied automatically — no manual ARIA configuration is needed.\n\n---\n\n## Keyboard Navigation\n\nThe Rating component supports full keyboard interaction following the [WAI-ARIA keyboard interaction guidelines](https://www.w3.org/WAI/ARIA/apg/patterns/slider/#keyboardinteraction):\n\n| Key | Action |\n|-----|--------|\n| `Arrow Up` | Increases the rating value |\n| `Arrow Right` | Increases the rating value (decreases in RTL mode) |\n| `Arrow Down` | Decreases the rating value |\n| `Arrow Left` | Decreases the rating value (increases in RTL mode) |\n| `Space` | When the **reset button** is focused, resets to `min` value |\n\n---\n\n## RTL Support\n\nEnable right-to-left layout using `enableRtl={true}`:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} enableRtl={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\nIn RTL mode:\n- Arrow Right **decreases** the value.\n- Arrow Left **increases** the value.\n- The component layout is mirrored.\n\n---\n\n## Ensuring Accessibility\n\nAccessibility compliance is verified through automated tools:\n\n- **[accessibility-checker](https://www.npmjs.com/package/accessibility-checker)** — automated WCAG/Section 508 validation.\n- **[axe-core](https://www.npmjs.com/package/axe-core)** — browser-based accessibility testing.\n\nThe Rating component passes both tools without configuration. To evaluate compliance in your app, run these tools against the page containing the rating component.\n\n---\n\n## Tips\n\n- Always provide a meaningful `aria-label` if the rating context isn't clear from surrounding text.\n- Combine `showLabel={true}` with the rating to give screen reader users a text representation of the current value.\n- Use `readOnly={true}` (not `disabled={true}`) for display-only ratings to keep them focusable and accessible.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3363,"content_sha256":"19cf7c653de4e8f0b1854a3ba1eefb70edbec31d66146eed926d406e9cb438ee"},{"filename":"references/rating-api.md","content":"# API Reference — Syncfusion React Rating Component\n\n**Source:** https://ej2.syncfusion.com/react/documentation/api/rating/index-default\n\n## Table of Contents\n- [Import](#import)\n- [Properties](#properties)\n- [Methods](#methods)\n- [Events](#events)\n- [Enums](#enums)\n- [Event Argument Interfaces](#event-argument-interfaces)\n\n---\n\n## Import\n\n```tsx\nimport {\n RatingComponent,\n PrecisionType,\n LabelPosition,\n RatingItemEventArgs,\n RatingHoverEventArgs,\n RatingChangedEventArgs,\n} from '@syncfusion/ej2-react-inputs';\n```\n\n---\n\n## Properties\n\n### allowReset\n**Type:** `boolean` | **Default:** `false`\n\nShows or hides the reset button. When `true`, the user can click the reset button to restore the rating to its minimum value.\n\n```tsx\n\u003cRatingComponent id=\"rating\" allowReset={true} value={3} />\n```\n\n---\n\n### cssClass\n**Type:** `string` | **Default:** `''`\n\nOne or more CSS classes to customize the component's appearance (colors, fonts, sizes, icon shapes, etc.).\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} cssClass=\"my-custom-rating\" />\n```\n\n---\n\n### disabled\n**Type:** `boolean` | **Default:** `false`\n\nDisables the component. When `true`, the user cannot interact with the rating, and the component may appear dimmed.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} disabled={true} />\n```\n\n---\n\n### emptyTemplate\n**Type:** `string | function | JSX.Element` | **Default:** `''`\n\nTemplate for the appearance of each **unrated** item. If `fullTemplate` is not defined, this template is used for both rated and unrated items.\n\n```tsx\nfunction emptyTemplate() {\n return \u003cspan className=\"custom-icon\">\u003c/span>;\n}\n\u003cRatingComponent id=\"rating\" value={3} emptyTemplate={emptyTemplate} />\n```\n\n---\n\n### enableAnimation\n**Type:** `boolean` | **Default:** `true`\n\nWhen `true`, a hover animation is shown when the user moves their cursor over rating items.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} enableAnimation={false} />\n```\n\n---\n\n### enablePersistence\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, the component's state (current value) is persisted across page reloads via browser local storage.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} enablePersistence={true} />\n```\n\n---\n\n### enableRtl\n**Type:** `boolean` | **Default:** `false`\n\nRenders the component in right-to-left direction. Arrow Left increases the value, Arrow Right decreases it.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} enableRtl={true} />\n```\n\n---\n\n### enableSingleSelection\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, only the clicked item is highlighted. When `false` (default), all items from the first to the selected item are highlighted.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} enableSingleSelection={true} />\n```\n\n---\n\n### fullTemplate\n**Type:** `string | function | JSX.Element` | **Default:** `''`\n\nTemplate for the appearance of each **rated** item.\n\n```tsx\nfunction fullTemplate() {\n return \u003cspan className=\"filled-icon\">\u003c/span>;\n}\n\u003cRatingComponent id=\"rating\" value={3} fullTemplate={fullTemplate} />\n```\n\n---\n\n### itemsCount\n**Type:** `number` | **Default:** `5`\n\nThe number of rating items (symbols) to display.\n\n```tsx\n\u003cRatingComponent id=\"rating\" itemsCount={10} value={7} />\n```\n\n---\n\n### labelPosition\n**Type:** `string | LabelPosition` | **Default:** `LabelPosition.Right`\n\nPosition of the value label relative to the rating. Requires `showLabel={true}`.\n\n**Possible values:** `'Top'`, `'Bottom'`, `'Left'`, `'Right'`\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} showLabel={true} labelPosition=\"Top\" />\n// or\n\u003cRatingComponent id=\"rating\" value={3} showLabel={true} labelPosition={LabelPosition.Top} />\n```\n\n---\n\n### labelTemplate\n**Type:** `string | function | JSX.Element` | **Default:** `''`\n\nCustom template for the label. The current `value` is available in the template context.\n\n```tsx\n\u003cRatingComponent\n id=\"rating\"\n value={3}\n showLabel={true}\n labelTemplate=\"\u003cspan>${value} out of 5\u003c/span>\"\n/>\n```\n\n---\n\n### locale\n**Type:** `string` | **Default:** `''`\n\nOverrides the global culture/localization. Default is `'en-US'`.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} locale=\"fr-FR\" />\n```\n\n---\n\n### min\n**Type:** `number` | **Default:** `0.0`\n\nThe minimum selectable rating value. Users cannot select a value below this.\n\n```tsx\n\u003cRatingComponent id=\"rating\" min={1} />\n```\n\n---\n\n### precision\n**Type:** `string | PrecisionType` | **Default:** `PrecisionType.Full`\n\nControls the granularity of the rating value.\n\n**Possible values:** `'Full'`, `'Half'`, `'Quarter'`, `'Exact'`\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={2.5} precision={PrecisionType.Half} />\n// or\n\u003cRatingComponent id=\"rating\" value={2.5} precision=\"Half\" />\n```\n\n---\n\n### readOnly\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, the component is non-interactive (user cannot change the value) but remains visible and focusable.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={4} readOnly={true} />\n```\n\n---\n\n### showLabel\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, displays a label showing the current rating value.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} showLabel={true} />\n```\n\n---\n\n### showTooltip\n**Type:** `boolean` | **Default:** `true`\n\nWhen `true`, shows a tooltip when the user hovers over a rating item.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} showTooltip={false} />\n```\n\n---\n\n### tooltipTemplate\n**Type:** `string | function | JSX.Element` | **Default:** `''`\n\nCustom template for tooltip content. The current `value` is available in the template context.\n\n```tsx\n\u003cRatingComponent\n id=\"rating\"\n value={3}\n showTooltip={true}\n tooltipTemplate=\"\u003cspan>${value} Star\u003c/span>\"\n/>\n```\n\n---\n\n### value\n**Type:** `number` | **Default:** `0.0`\n\nThe current rating value. Ranges from `min` to `itemsCount`. Supports decimals based on `precision`.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3.5} />\n```\n\n---\n\n### visible\n**Type:** `boolean` | **Default:** `true`\n\nControls component visibility. When `false`, the component is hidden.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} visible={true} />\n```\n\n---\n\n## Methods\n\n### destroy()\n**Returns:** `void`\n\nDestroys the Rating component instance and cleans up DOM elements and event listeners.\n\n```tsx\nconst ratingRef = React.useRef\u003cRatingComponent>(null);\nratingRef.current?.destroy();\n```\n\n---\n\n### reset()\n**Returns:** `void`\n\nResets the rating value to the `min` value.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const ratingRef = React.useRef\u003cRatingComponent>(null);\n\n return (\n \u003cdiv>\n \u003cRatingComponent id=\"rating\" min={1} value={3} ref={ratingRef} />\n \u003cbutton onClick={() => ratingRef.current?.reset()}>Reset\u003c/button>\n \u003c/div>\n );\n}\n```\n\n---\n\n## Events\n\n### beforeItemRender\n**Type:** `EmitType\u003cRatingItemEventArgs>`\n\nRaised before rendering each rating item. Use to customize items at render time.\n\n```tsx\n\u003cRatingComponent id=\"rating\" beforeItemRender={(args: RatingItemEventArgs) => { /* ... */ }} />\n```\n\n---\n\n### created\n**Type:** `EmitType\u003cEvent>`\n\nRaised after the rating component has fully rendered.\n\n```tsx\n\u003cRatingComponent id=\"rating\" created={() => console.log('Ready')} />\n```\n\n---\n\n### onItemHover\n**Type:** `EmitType\u003cRatingHoverEventArgs>`\n\nRaised when the user hovers over a rating item.\n\n```tsx\n\u003cRatingComponent id=\"rating\" onItemHover={(args: RatingHoverEventArgs) => console.log(args.value)} />\n```\n\n---\n\n### valueChanged\n**Type:** `EmitType\u003cRatingChangedEventArgs>`\n\nRaised when the selected rating value changes.\n\n```tsx\n\u003cRatingComponent\n id=\"rating\"\n valueChanged={(args: RatingChangedEventArgs) => {\n console.log('Previous:', args.previousValue, 'New:', args.value);\n }}\n/>\n```\n\n---\n\n## Enums\n\n### PrecisionType\n\n```tsx\nimport { PrecisionType } from '@syncfusion/ej2-react-inputs';\n```\n\n| Value | Increment | Description |\n|-------|-----------|-------------|\n| `PrecisionType.Full` | 1.0 | Whole number increments (default) |\n| `PrecisionType.Half` | 0.5 | Half increments |\n| `PrecisionType.Quarter` | 0.25 | Quarter increments |\n| `PrecisionType.Exact` | 0.1 | Tenth increments |\n\n---\n\n### LabelPosition\n\n```tsx\nimport { LabelPosition } from '@syncfusion/ej2-react-inputs';\n```\n\n| Value | Description |\n|-------|-------------|\n| `LabelPosition.Top` | Label above the rating |\n| `LabelPosition.Bottom` | Label below the rating |\n| `LabelPosition.Left` | Label to the left of the rating |\n| `LabelPosition.Right` | Label to the right of the rating (default) |\n\n---\n\n## Event Argument Interfaces\n\n### RatingItemEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `element` | `HTMLElement` | The rating item's DOM element |\n| `value` | `number` | The value of the item |\n| `index` | `number` | Zero-based index of the item |\n\n### RatingHoverEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `element` | `HTMLElement` | The hovered item's DOM element |\n| `value` | `number` | The value of the hovered item |\n\n### RatingChangedEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `number` | The newly selected rating value |\n| `previousValue` | `number` | The previously selected rating value |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9229,"content_sha256":"c594d4c1b0dab0cc09ada8cb8f22de6873be8feabd7c0e6ddf33733e41b291a5"},{"filename":"references/rating-appearance.md","content":"# Appearance and Customization in React Rating Component\n\n## Table of Contents\n- [Items Count](#items-count)\n- [Disabled State](#disabled-state)\n- [Visible / Hidden](#visible--hidden)\n- [Read-Only Mode](#read-only-mode)\n- [CSS Customization with cssClass](#css-customization-with-cssclass)\n - [Changing Border Color](#changing-border-color)\n - [Changing Fill Colors](#changing-fill-colors)\n - [Changing Item Spacing](#changing-item-spacing)\n - [Changing the Rating Icon](#changing-the-rating-icon)\n- [Animation](#animation)\n\n---\n\n## Items Count\n\nControl the number of rating symbols with `itemsCount`. Default is `5`.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" itemsCount={8} value={3} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Disabled State\n\nSet `disabled={true}` to prevent user interaction. The component shows a dimmed visual appearance.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} disabled={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Disabled is different from read-only: disabled components are visually dimmed and not focusable.\n\n---\n\n## Visible / Hidden\n\nUse `visible` to show or hide the rating component. Default is `true`.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const ratingRef = React.useRef\u003cRatingComponent>(null);\n\n const toggleVisible = () => {\n if (ratingRef.current) {\n ratingRef.current.visible = !ratingRef.current.visible;\n }\n };\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cbutton onClick={toggleVisible}>Toggle Visible\u003c/button>\n \u003cRatingComponent id=\"rating\" value={3} visible={true} ref={ratingRef} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Read-Only Mode\n\nUse `readOnly={true}` to display the rating without allowing changes. The component is still visible and focusable but non-interactive.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} readOnly={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Use `readOnly` for **display-only** rating (e.g., showing an average score).\n- Use `disabled` when the rating field is conditionally unavailable.\n\n---\n\n## CSS Customization with cssClass\n\nPass a custom CSS class via `cssClass` and override the relevant CSS variables or properties.\n\n### Changing Border Color\n\nChange the icon outline/stroke color using `.e-rating-icon` with `text-stroke` (or `-webkit-text-stroke`):\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} cssClass=\"custom-border\" />\n```\n\n```css\n.custom-border .e-rating-icon {\n -webkit-text-stroke: 2px #ff0000;\n}\n```\n\n---\n\n### Changing Fill Colors\n\nCustomize rated (filled) and unrated (empty) fill colors using `linear-gradient` on `.e-rating-icon`. The first color-stop is the rated color, the second is the unrated color. `--rating-value` provides the current item's value for partial fill support.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} cssClass=\"custom-fill\" />\n```\n\n```css\n.custom-fill .e-rating-icon {\n background: linear-gradient(\n to right,\n #ffe814 calc(var(--rating-value) * 100%),\n #d8d7d4 calc(var(--rating-value) * 100%)\n );\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n}\n```\n\n---\n\n### Changing Item Spacing\n\nAdjust spacing between rating items by targeting `.e-rating-item-container`:\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} cssClass=\"custom-spacing\" />\n```\n\n```css\n.custom-spacing .e-rating-item-container {\n margin: 0 8px;\n}\n```\n\n---\n\n### Changing the Rating Icon\n\nReplace the default star with any font icon by overriding `.e-icons.e-star-filled:before`:\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} cssClass=\"custom-icon\" />\n```\n\n```css\n.custom-icon .e-icons.e-star-filled:before {\n content: '\\e700'; /* Replace with your font icon code */\n font-family: 'YourIconFont';\n}\n```\n\n---\n\n## Animation\n\nThe `enableAnimation` property controls whether items animate on hover. Default is `true`.\n\n```tsx\n{/* Disable hover animation */}\n\u003cRatingComponent id=\"rating\" value={3} enableAnimation={false} />\n```\n\n- Disable animation when using custom emoji or SVG templates to avoid visual conflicts.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4566,"content_sha256":"d67863d27cf55df2bbe67f27587cf8ca0477b647b224b8161bc653c4040340a7"},{"filename":"references/rating-events.md","content":"# Events in React Rating Component\n\n## Table of Contents\n- [beforeItemRender](#beforeitemrender)\n- [created](#created)\n- [onItemHover](#onitemhover)\n- [valueChanged](#valuechanged)\n- [Event Arguments Reference](#event-arguments-reference)\n\n---\n\n## beforeItemRender\n\nFires before each rating item is rendered. Use it to customize or inspect items before they appear.\n\n```tsx\nimport { RatingComponent, RatingItemEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function beforeItemRender(args: RatingItemEventArgs) {\n // args.element — the item DOM element\n // args.value — the value of this item\n // args.index — the zero-based index of this item\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" beforeItemRender={beforeItemRender} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Called once per item during initial render and on re-render.\n- Useful for conditionally applying classes or attributes to specific items.\n\n---\n\n## created\n\nFires after the rating component has fully rendered.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function created() {\n console.log('Rating component is ready');\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" created={created} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Use for post-render initialization logic.\n- The event receives a standard DOM `Event` object.\n\n---\n\n## onItemHover\n\nFires when the user hovers over a rating item. Provides the hovered item's details.\n\n```tsx\nimport { RatingComponent, RatingHoverEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const [hovered, setHovered] = React.useState\u003cnumber | null>(null);\n\n function onItemHover(args: RatingHoverEventArgs) {\n setHovered(args.value);\n // args.value — the value of the hovered item\n // args.element — the hovered item DOM element\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" onItemHover={onItemHover} />\n {hovered !== null && \u003cp>Hovering over: {hovered}\u003c/p>}\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Useful for live previews: show a label or description as the user moves their cursor.\n\n---\n\n## valueChanged\n\nFires when the user selects a new rating value. Provides both the previous and new values.\n\n```tsx\nimport { RatingComponent, RatingChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function valueChanged(args: RatingChangedEventArgs) {\n console.log('Previous:', args.previousValue);\n console.log('New value:', args.value);\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" valueChanged={valueChanged} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Practical example — display previous and new values:**\n\n```tsx\nimport { RatingComponent, RatingChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const [info, setInfo] = React.useState('');\n\n function valueChanged(args: RatingChangedEventArgs) {\n setInfo(`Changed from ${args.previousValue} to ${args.value}`);\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" valueChanged={valueChanged} />\n \u003cp>{info}\u003c/p>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Event Arguments Reference\n\n### RatingItemEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `element` | `HTMLElement` | The rating item DOM element |\n| `value` | `number` | The value of the item |\n| `index` | `number` | Zero-based item index |\n\n### RatingHoverEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `element` | `HTMLElement` | The hovered item DOM element |\n| `value` | `number` | The value of the hovered item |\n\n### RatingChangedEventArgs\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `number` | The newly selected rating value |\n| `previousValue` | `number` | The previously selected rating value |\n\n---\n\n## Event Import Reference\n\n```tsx\nimport {\n RatingComponent,\n RatingItemEventArgs,\n RatingHoverEventArgs,\n RatingChangedEventArgs,\n} from '@syncfusion/ej2-react-inputs';\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4332,"content_sha256":"577b46873cb2d39adb3461ba6b3f16b2e9d71efdd3fbda78fabaeb2c17b2a64b"},{"filename":"references/rating-getting-started.md","content":"# Getting Started with Syncfusion React Rating\n\n## Table of Contents\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n- [CSS Reference](#css-reference)\n- [Basic Usage](#basic-usage)\n- [Setting Initial Value](#setting-initial-value)\n- [Running the Application](#running-the-application)\n\n---\n\n## Prerequisites\n\nCreate a React application using Vite:\n\n```bash\n# TypeScript\nnpm create vite@latest my-app -- --template react-ts\ncd my-app\nnpm run dev\n\n# JavaScript\nnpm create vite@latest my-app -- --template react\ncd my-app\nnpm run dev\n```\n\n---\n\n## Installation\n\nInstall the Syncfusion inputs package that includes the Rating component:\n\n```bash\nnpm install @syncfusion/ej2-react-inputs --save\n```\n\n> The `--save` flag adds the package to the `dependencies` section of `package.json`.\n\n---\n\n## CSS Reference\n\nAdd the required CSS imports to `src/App.css`:\n\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/rating/index.css\";\n```\n\nThen import `App.css` in `src/App.tsx`:\n\n```tsx\nimport './App.css';\n```\n\n> Three CSS files are needed: `ej2-base` for core styles, `ej2-react-inputs` for rating styles, and `ej2-popups` for tooltip styles.\n\n---\n\n## Basic Usage\n\nAdd the `RatingComponent` to `src/App.tsx`:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cRatingComponent id=\"rating\" />\n );\n}\nexport default App;\n```\n\nThis renders a 5-star rating with no initial selection and a tooltip on hover.\n\n---\n\n## Setting Initial Value\n\nUse the `value` property to set a pre-selected rating:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- `value` is a decimal ranging from `min` (default `0`) to `itemsCount` (default `5`).\n- Example: `value={3.5}` with `precision={PrecisionType.Half}` shows a half-star at position 4.\n\n---\n\n## Running the Application\n\n```bash\nnpm run dev\n```\n\nThe application opens in your browser. The rating component is interactive by default — click a star to select a rating, hover to see tooltips.\n\n---\n\n## Gotchas\n\n- Always import `App.css` (with the three CSS imports) in your root component or the component will render unstyled.\n- The `id` prop is required for the rating component to function correctly.\n- `@syncfusion/ej2-popups` CSS is required even if tooltips are disabled, to avoid layout issues.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2592,"content_sha256":"12afc971c8b289d2d84e7d19bca29a5eb979966478d33e1e69f8417452d9e23b"},{"filename":"references/rating-labels.md","content":"# Labels in React Rating Component\n\nShow the current rating value as a label and control its position and format.\n\n---\n\n## Showing the Label\n\nSet `showLabel={true}` to display a label showing the current rating value.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} showLabel={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Default is `false` (label hidden).\n- By default the label appears to the **Right** of the rating.\n\n---\n\n## Label Position\n\nUse `labelPosition` to control where the label appears. Import the `LabelPosition` enum for type safety.\n\n**Supported positions:** `Top`, `Bottom`, `Left`, `Right`\n\n```tsx\nimport { RatingComponent, LabelPosition } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003clabel>Left\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating1\" value={3} showLabel={true} labelPosition={LabelPosition.Left} />\u003cbr />\n\n \u003clabel>Right\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating2\" value={3} showLabel={true} labelPosition={LabelPosition.Right} />\u003cbr />\n\n \u003clabel>Top\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating3\" value={3} showLabel={true} labelPosition={LabelPosition.Top} />\u003cbr />\n\n \u003clabel>Bottom\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating4\" value={3} showLabel={true} labelPosition={LabelPosition.Bottom} />\u003cbr />\n \u003c/div>\n );\n}\nexport default App;\n```\n\nYou can also pass string values: `labelPosition=\"Left\"`, `labelPosition=\"Top\"`, etc.\n\n---\n\n## Label Template\n\nUse `labelTemplate` to display custom content in the label. The current `value` is available in the template context.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={3}\n showLabel={true}\n labelTemplate=\"\u003cspan>${value} out of 5\u003c/span>\"\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Template string uses `${value}` to inject the current rating value.\n- The label updates dynamically as the user changes the rating.\n\n---\n\n## Common Patterns\n\n| Goal | Configuration |\n|------|---------------|\n| Show numeric value | `showLabel={true}` |\n| Label above the rating | `labelPosition={LabelPosition.Top}` |\n| Label below the rating | `labelPosition={LabelPosition.Bottom}` |\n| Show \"X out of 5\" | `labelTemplate=\"\u003cspan>${value} out of 5\u003c/span>\"` |\n| Show descriptive text | Custom `labelTemplate` with conditional logic |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2671,"content_sha256":"920f19506826491698ac6b52fadaeabe96e5a951226ab051be240c64669fa8f5"},{"filename":"references/rating-precision-modes.md","content":"# Precision Modes in React Rating Component\n\nControl how finely users can select rating values using the `precision` property with the `PrecisionType` enum.\n\n## Supported Precision Types\n\n| Type | Increment | Example values |\n|------|-----------|----------------|\n| `Full` (default) | 1.0 | 1, 2, 3, 4, 5 |\n| `Half` | 0.5 | 2.5, 3.0, 3.5, 4.0 |\n| `Quarter` | 0.25 | 3.75, 4.0, 4.25, 4.5 |\n| `Exact` | 0.1 | 3.9, 4.0, 4.1, 4.2 |\n\n---\n\n## All Precision Types Together\n\n```tsx\nimport { RatingComponent, PrecisionType } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003clabel>Full Precision\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating1\" value={3} precision={PrecisionType.Full} />\u003cbr />\n\n \u003clabel>Half Precision\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating2\" value={2.5} precision={PrecisionType.Half} />\u003cbr />\n\n \u003clabel>Quarter Precision\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating3\" value={3.75} precision={PrecisionType.Quarter} />\u003cbr />\n\n \u003clabel>Exact Precision\u003c/label>\u003cbr />\n \u003cRatingComponent id=\"rating4\" value={2.3} precision={PrecisionType.Exact} />\u003cbr />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Full Precision (Default)\n\nRatings snap to whole numbers. Most common for simple star ratings.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} precision={PrecisionType.Full} />\n```\n\n---\n\n## Half Precision\n\nRatings snap to 0.5 increments. Useful for movie/product ratings where half stars are needed.\n\n```tsx\nimport { RatingComponent, PrecisionType } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cRatingComponent id=\"rating\" value={3.5} precision={PrecisionType.Half} />\n );\n}\nexport default App;\n```\n\n---\n\n## Quarter Precision\n\nRatings snap to 0.25 increments. Use when finer granularity than half is needed.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3.75} precision={PrecisionType.Quarter} />\n```\n\n---\n\n## Exact Precision\n\nRatings snap to 0.1 increments. Use when very fine-grained ratings are required.\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={2.3} precision={PrecisionType.Exact} />\n```\n\n---\n\n## Tips\n\n- The `precision` property also accepts string values: `'Full'`, `'Half'`, `'Quarter'`, `'Exact'`.\n- When using templates (`emptyTemplate`/`fullTemplate`), use the CSS variable `--rating-value` or the `value` from template context to support visual partial fills.\n- Combine `precision={PrecisionType.Half}` with `showLabel={true}` to display the exact decimal value (e.g., \"3.5\").\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2569,"content_sha256":"32f8507322390c6f243b156cfcb21ecb07fae595dadd60fb98bd8f4a3425649b"},{"filename":"references/rating-selection.md","content":"# Selection in React Rating Component\n\n## Table of Contents\n- [Basic Value Selection](#basic-value-selection)\n- [Minimum Value](#minimum-value)\n- [Single Selection Mode](#single-selection-mode)\n- [Reset Button](#reset-button)\n- [Programmatic Reset](#programmatic-reset)\n\n---\n\n## Basic Value Selection\n\nSet the current rating value using the `value` property. The value is a decimal number ranging from `min` to `itemsCount`.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Default `value` is `0.0` (no selection).\n- The selected items are highlighted up to the chosen value.\n\n---\n\n## Minimum Value\n\nUse the `min` property to set the minimum selectable rating. Users cannot rate below this value.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n {/* Users can only select 2 or higher */}\n \u003cRatingComponent id=\"rating\" min={2} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Default `min` is `0.0`.\n- The reset button resets to the `min` value (not necessarily 0).\n\n---\n\n## Single Selection Mode\n\nEnable `enableSingleSelection` to highlight only the clicked item rather than all items up to it.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} enableSingleSelection={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Default is `false` — items fill from the first item to the selected item.\n- When `true`, only the clicked item is highlighted; all others are unselected.\n- Useful for discrete emotion/mood pickers (e.g., emoji templates).\n\n---\n\n## Reset Button\n\nShow a reset button by setting `allowReset={true}`. Clicking it resets the rating to its `min` value.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} allowReset={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- Default is `false` (reset button hidden).\n- The reset button has `role=\"button\"` and `aria-hidden` for accessibility.\n- Keyboard: press `Space` when the reset button is focused to reset.\n\n---\n\n## Programmatic Reset\n\nUse the `reset()` method via a ref to reset the rating programmatically:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const ratingRef = React.useRef\u003cRatingComponent>(null);\n\n const handleReset = () => {\n ratingRef.current?.reset();\n };\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" min={1} value={3} ref={ratingRef} />\n \u003cbutton onClick={handleReset}>Reset\u003c/button>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n- `reset()` sets the value back to `min` (default `0`).\n- Use `min={1}` if you want the reset to land on 1 instead of 0.\n\n---\n\n## Common Use Cases\n\n| Scenario | Configuration |\n|----------|---------------|\n| Simple 1-5 star rating | `value={3}` |\n| Rating that can't go below 1 | `min={1}` |\n| Emotion picker (single icon highlight) | `enableSingleSelection={true}` |\n| Clearable rating | `allowReset={true}` |\n| Reset via button click | `ref={ratingRef}` → `ratingRef.current?.reset()` |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3554,"content_sha256":"2081bbe0c6a7a02f1e706226779e4fcb7051c4a60cac57f2c03d4f9d957ecb08"},{"filename":"references/rating-templates.md","content":"# Templates in React Rating Component\n\n## Table of Contents\n- [Overview](#overview)\n- [Empty Template (Unrated Items)](#empty-template-unrated-items)\n- [Full Template (Rated Items)](#full-template-rated-items)\n- [Emoji Rating Symbols](#emoji-rating-symbols)\n- [SVG Icon Rating Symbols](#svg-icon-rating-symbols)\n- [PNG Image Rating Symbols](#png-image-rating-symbols)\n- [Precision Support in Templates](#precision-support-in-templates)\n\n---\n\n## Overview\n\nThe Rating component supports two template directives:\n\n| Template | Purpose |\n|----------|---------|\n| `emptyTemplate` | Appearance of **unrated** items |\n| `fullTemplate` | Appearance of **rated** items |\n\nIf only `emptyTemplate` is provided, it is used for both rated and unrated items — apply CSS to differentiate states.\n\nTemplates receive context with `value` (current item value) and `index` (0-based item position).\n\n---\n\n## Empty Template (Unrated Items)\n\nCustomize unrated item appearance using a render function as `emptyTemplate`:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function emptyTemplate() {\n return (\n \u003cReact.Fragment>\n \u003cspan className=\"custom-font sf-rating-heart\">\u003c/span>\n \u003c/React.Fragment>\n );\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} emptyTemplate={emptyTemplate} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Full Template (Rated Items)\n\nProvide both `emptyTemplate` and `fullTemplate` to control rated and unrated items independently:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function emptyTemplate() {\n return (\n \u003cReact.Fragment>\n \u003cspan className=\"custom-font sf-icon-empty-star\">\u003c/span>\n \u003c/React.Fragment>\n );\n }\n\n function fullTemplate() {\n return (\n \u003cReact.Fragment>\n \u003cspan className=\"custom-font sf-icon-fill-star\">\u003c/span>\n \u003c/React.Fragment>\n );\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={3}\n emptyTemplate={emptyTemplate}\n fullTemplate={fullTemplate}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Emoji Rating Symbols\n\nUse emojis as rating symbols. Access the `index` from template context to return different emojis per position. Enable `enableSingleSelection` for discrete emoji selection and disable `enableAnimation` to prevent animation conflicts:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function emptyTemplate(props: { index: number }) {\n const emojis = ['😡', '🙁', '😐', '🙂', '😀'];\n const classes = ['angry', 'disagree', 'neutral', 'agree', 'happy'];\n return (\n \u003cspan className={`${classes[props.index]} emoji`}>\n {emojis[props.index]}\n \u003c/span>\n );\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={3}\n emptyTemplate={emptyTemplate}\n enableSingleSelection={true}\n enableAnimation={false}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## SVG Icon Rating Symbols\n\nUse SVG elements as rating symbols. Access `index` in the template to create unique gradient IDs per item:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function emptyTemplate() {\n return (\n \u003csvg width=\"35\" height=\"25\" className=\"e-rating-svg-icon\">\n \u003crect width=\"35\" height=\"25\" fill=\"transparent\" strokeWidth=\"2\" stroke=\"rgb(173,181,189)\" />\n \u003c/svg>\n );\n }\n\n function fullTemplate(props: { index: number }) {\n return (\n \u003csvg width=\"35\" height=\"25\" className=\"e-rating-svg-icon\">\n \u003cdefs>\n \u003clinearGradient id={`grad${props.index}`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n \u003cstop className=\"start\" offset=\"0%\" />\n \u003cstop className=\"end\" offset=\"100%\" />\n \u003c/linearGradient>\n \u003c/defs>\n \u003crect\n width=\"35\"\n height=\"25\"\n fill={`url(#grad${props.index})`}\n strokeWidth=\"2\"\n stroke=\"rgb(173,181,189)\"\n />\n \u003c/svg>\n );\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={4}\n emptyTemplate={emptyTemplate}\n fullTemplate={fullTemplate}\n enableAnimation={false}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## PNG Image Rating Symbols\n\nUse PNG images as rating symbols:\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function emptyTemplate() {\n return (\n \u003cimg\n src=\"/images/star-empty.png\"\n width=\"25\"\n height=\"25\"\n alt=\"empty star\"\n />\n );\n }\n\n function fullTemplate() {\n return (\n \u003cimg\n src=\"/images/star-filled.png\"\n width=\"25\"\n height=\"25\"\n alt=\"filled star\"\n />\n );\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={4}\n emptyTemplate={emptyTemplate}\n fullTemplate={fullTemplate}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Precision Support in Templates\n\nWhen using templates with precision modes (half, quarter, exact), use the CSS variable `--rating-value` or the `value` from the template context to apply partial fills:\n\n```css\n/* Apply partial fill based on item value */\n.e-rating-item-container {\n --rating-value: 0; /* set by the component per item */\n}\n\n.my-template-icon {\n background: linear-gradient(\n to right,\n gold calc(var(--rating-value) * 100%),\n lightgray calc(var(--rating-value) * 100%)\n );\n}\n```\n\n> The `value` in the template context represents how much of that specific item should be \"filled\" (0 to 1), which enables partial fill rendering for fractional ratings.\n\n---\n\n## Tips\n\n- Use `enableAnimation={false}` with emoji or image templates to avoid visual glitches.\n- Use `enableSingleSelection={true}` with emoji templates for discrete mood pickers.\n- Always set unique gradient IDs when using SVG templates with multiple items.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6260,"content_sha256":"ffda8c8ce1a2f19bc1db06682753ed42d9724d1db3895611cc58d51064d63684"},{"filename":"references/rating-tooltip.md","content":"# Tooltip in React Rating Component\n\nDisplay contextual tooltips when users hover over rating items.\n\n---\n\n## Enabling Tooltips\n\nSet `showTooltip={true}` to show tooltips on item hover. The default value is `true`, so tooltips are shown out of the box.\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent id=\"rating\" value={3} showTooltip={true} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\nTo hide tooltips:\n\n```tsx\n\u003cRatingComponent id=\"rating\" value={3} showTooltip={false} />\n```\n\n---\n\n## Custom Tooltip Content (tooltipTemplate)\n\nUse `tooltipTemplate` to replace the default tooltip with custom content. The current `value` is available in the template context.\n\n**String template:**\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={3}\n showTooltip={true}\n tooltipTemplate=\"\u003cspan>${value} Star\u003c/span>\"\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Function template (conditional content by value):**\n\n```tsx\nimport { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function tooltipTemplate(props: { value: number }) {\n const labels: Record\u003cnumber, string> = {\n 1: 'Angry',\n 2: 'Sad',\n 3: 'Neutral',\n 4: 'Good',\n 5: 'Happy',\n };\n return \u003cb>{labels[props.value] ?? props.value}\u003c/b>;\n }\n\n return (\n \u003cdiv className=\"wrap\">\n \u003cRatingComponent\n id=\"rating\"\n value={3}\n showTooltip={true}\n tooltipTemplate={tooltipTemplate}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Tooltip Appearance (cssClass)\n\nCustomize the tooltip's visual style using `cssClass` and targeting the Syncfusion tooltip CSS classes:\n\n```tsx\n\u003cRatingComponent\n id=\"rating\"\n value={3}\n showTooltip={true}\n cssClass=\"customtooltip\"\n/>\n```\n\n```css\n.customtooltip.e-tooltip-wrap {\n background-color: #333;\n border-color: #333;\n border-radius: 4px;\n}\n.customtooltip.e-tooltip-wrap .e-tip-content {\n color: #fff;\n font-size: 14px;\n}\n```\n\n---\n\n## Common Patterns\n\n| Goal | Configuration |\n|------|---------------|\n| Show value as tooltip | `showTooltip={true}` (default) |\n| Hide tooltips | `showTooltip={false}` |\n| Show descriptive text | `tooltipTemplate` with value-based labels |\n| Style the tooltip | `cssClass=\"customtooltip\"` + CSS overrides |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2588,"content_sha256":"6a7f538eaa7949856a19aaadbac5375e3f31546792365968db9e5d9d47eaabf3"},{"filename":"references/signature-accessibility.md","content":"# Accessibility in Syncfusion React Signature\n\nThe Signature component is designed to meet accessibility standards for use with assistive technologies and keyboard-only navigation.\n\n---\n\n## Compliance Overview\n\n| Accessibility Criteria | Support |\n|------------------------|---------|\n| WCAG 2.2 | ✅ Full |\n| Section 508 | ✅ Full |\n| Screen Reader Support | ✅ Full |\n| Right-To-Left Support | N/A |\n| Color Contrast | ✅ Full |\n| Mobile Device Support | ✅ Full |\n| Keyboard Navigation Support | ✅ Full |\n| Accessibility Checker Validation | ✅ Full |\n| Axe-core Accessibility Validation | ✅ Full |\n\n---\n\n## Keyboard Interaction\n\nThe Signature component supports the following keyboard shortcuts when the canvas has focus:\n\n| Key | Action |\n|-----|--------|\n| `Ctrl + Z` | Undo the last stroke/action |\n| `Ctrl + Y` | Redo the last undone action |\n| `Ctrl + S` | Save the signature (triggers `beforeSave` event) |\n| `Delete` | Clear all signature strokes from the canvas |\n\n> **Note:** `Ctrl + S` raises the `beforeSave` event, which allows you to customize the file name and type before the download occurs. This event is only triggered via keyboard — not when calling `save()` programmatically.\n\n---\n\n## Screen Reader Support\n\nThe Signature canvas is equipped with appropriate ARIA roles and labels so screen readers can announce the component's state and purpose to users who rely on assistive technology.\n\n---\n\n## Mobile Device Support\n\nThe component captures input from touch events (finger or stylus), making it fully functional on tablets and touchscreen devices. Pointer events handle both mouse and touch seamlessly.\n\n---\n\n## Ensuring Accessibility\n\nAccessibility compliance is verified using:\n- [`accessibility-checker`](https://www.npmjs.com/package/accessibility-checker) — for automated WCAG/Section 508 checks\n- [`axe-core`](https://www.npmjs.com/package/axe-core) — for DOM-based accessibility rule validation\n\nThese tools are used during automated testing of the component. You can run them against your own pages to verify integration-level compliance.\n\n---\n\n## Best Practices\n\n- Always provide a visible label or heading (e.g., `\u003ch4>Sign here\u003c/h4>`) near the signature canvas so keyboard and screen reader users understand the context.\n- Do not rely on color alone to communicate instructions — use text labels alongside color-coded controls.\n- Ensure sufficient color contrast between `strokeColor` and `backgroundColor` (minimum 3:1 ratio for large UI elements).\n- When integrating with a toolbar, make sure toolbar buttons are keyboard-focusable and have descriptive `tooltipText` values.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2631,"content_sha256":"c15110c32843dc4c975ba69b19541ac77c0dd00920cc49b24c9a3ff020a0657f"},{"filename":"references/signature-api.md","content":"# API Reference — Syncfusion React Signature\n\nSource: https://ej2.syncfusion.com/react/documentation/api/signature/index-default\n\n## Table of Contents\n- [Properties](#properties)\n- [Methods](#methods)\n- [Events](#events)\n- [Types](#types)\n\n---\n\n## Properties\n\n### `backgroundColor`\n- **Type:** `string`\n- **Default:** `''`\n- Gets or sets the background color of the canvas. Accepts hex codes (`#ffffff`), RGB (`rgb(255,255,255)`), or CSS color names (`white`). An empty string renders the canvas with a transparent/default background.\n\n### `backgroundImage`\n- **Type:** `string`\n- **Default:** `''`\n- Gets or sets the background image for the canvas. Accepts a hosted URL or a base64-encoded image string. An empty string means no background image.\n\n### `disabled`\n- **Type:** `boolean`\n- **Default:** `false`\n- Gets or sets whether the component is disabled. When `true`, the component is non-interactive and displayed with reduced opacity. Cannot receive focus while disabled.\n\n### `enablePersistence`\n- **Type:** `boolean`\n- **Default:** `false`\n- Gets or sets whether to persist the component state between page reloads. When `true`, the last signature value is stored in browser local storage and restored on reload.\n\n### `isReadOnly`\n- **Type:** `boolean`\n- **Default:** `false`\n- Gets or sets whether the component is in read-only mode. When `true`, the component can receive focus but no new strokes can be drawn. Use to display an existing signature without allowing edits.\n\n### `maxStrokeWidth`\n- **Type:** `number`\n- **Default:** `2`\n- Gets or sets the maximum stroke width. The component calculates variable stroke width using `maxStrokeWidth`, `minStrokeWidth`, and `velocity`.\n\n### `minStrokeWidth`\n- **Type:** `number`\n- **Default:** `0.5`\n- Gets or sets the minimum stroke width. Works together with `maxStrokeWidth` and `velocity` to create natural stroke variation.\n\n### `saveWithBackground`\n- **Type:** `boolean`\n- **Default:** `true`\n- Gets or sets whether to save the signature including its background color and background image. When `false`, only the stroke content is saved (transparent background for PNG).\n\n### `signatureValue`\n- **Type:** `string`\n- Gets or sets the last signature URL to maintain persisted state. Used internally for `enablePersistence`.\n\n### `strokeColor`\n- **Type:** `string`\n- **Default:** `'#000000'`\n- Gets or sets the color of the signature strokes. Accepts hex codes, RGB values, or CSS color names.\n\n### `velocity`\n- **Type:** `number`\n- **Default:** `0.7`\n- Gets or sets the velocity factor used to calculate stroke width variation based on drawing speed. Values between 0 and 1; lower values produce greater width variation between slow and fast strokes.\n\n---\n\n## Methods\n\n### `canRedo()`\n- **Returns:** `boolean`\n- Returns `true` if the redo history contains actions that can be reapplied. Call before invoking `redo()` to avoid no-op calls.\n\n### `canUndo()`\n- **Returns:** `boolean`\n- Returns `true` if the undo history contains actions that can be reverted. Call before invoking `undo()` to avoid no-op calls.\n\n### `clear()`\n- **Returns:** `void`\n- Erases all signature strokes from the canvas. This action is added to the undo history, so the user can undo a clear.\n\n### `destroy()`\n- **Returns:** `void`\n- Removes the component from the DOM and detaches all related event handlers. Restores the original input element in the DOM.\n\n### `draw(text, fontFamily?, fontSize?)`\n- **Returns:** `void`\n- Renders a text string onto the canvas as a typed signature.\n- **Parameters:**\n - `text` (string) — the text to draw\n - `fontFamily` (string, optional) — font family, default `'Arial'`\n - `fontSize` (number, optional) — font size in pixels, default `30`\n\n### `getBlob(url)`\n- **Returns:** `Blob`\n- Converts the given base64 string or URL to a `Blob` object.\n- **Parameters:**\n - `url` (string) — a base64 string or URL of the signature\n\n### `getSignature(type?)`\n- **Returns:** `string`\n- Returns the current canvas content as a base64-encoded string.\n- **Parameters:**\n - `type` (SignatureFileType, optional) — `'Png'` | `'Jpeg'` | `'Svg'`, default `'Png'`\n\n### `isEmpty()`\n- **Returns:** `boolean`\n- Returns `true` if the canvas contains no signature strokes. Use to guard `clear()` calls or disable save/clear buttons.\n\n### `load(signature, width?, height?)`\n- **Returns:** `void`\n- Loads a signature image onto the canvas from a base64 string or a hosted URL.\n- **Parameters:**\n - `signature` (string) — base64 string or URL of the PNG/JPEG/SVG image\n - `width` (number, optional) — width at which to render the loaded image\n - `height` (number, optional) — height at which to render the loaded image\n\n### `redo()`\n- **Returns:** `void`\n- Reapplies the most recently undone action. Check `canRedo()` before calling.\n\n### `refresh()`\n- **Returns:** `void`\n- Refreshes the Signature component, re-rendering it in its current state. Useful after container resizing.\n\n### `save(type?, fileName?)`\n- **Returns:** `void`\n- Downloads the signature as an image file to the user's browser.\n- **Parameters:**\n - `type` (SignatureFileType, optional) — `'Png'` | `'Jpeg'` | `'Svg'`, default `'Png'`\n - `fileName` (string, optional) — name of the downloaded file (without extension)\n\n### `saveAsBlob()`\n- **Returns:** `Blob`\n- Returns the current canvas content as a `Blob` object (binary data). Use for file upload, FormData, or database storage.\n\n### `undo()`\n- **Returns:** `void`\n- Reverts the most recent action. Check `canUndo()` before calling.\n\n---\n\n## Events\n\n### `beforeSave`\n- **Type:** `EmitType\u003cSignatureBeforeSaveEventArgs>`\n- Raised before the signature is saved via the keyboard shortcut `Ctrl + S`. Use `SignatureBeforeSaveEventArgs` to customize the `fileName` and `type` (`SignatureFileType`) before the download occurs.\n- **Note:** This event is only triggered by the keyboard shortcut — not when calling `save()` programmatically.\n\n### `change`\n- **Type:** `EmitType\u003cSignatureChangeEventArgs>`\n- Raised after every user action: completing a stroke, undo, redo, and clear. Use this event to update dependent UI elements such as toolbar button states.\n\n### `created`\n- **Type:** `EmitType\u003cEvent>`\n- Triggered once, after the component has finished rendering. Use to initialize dependent controls or set initial state.\n\n---\n\n## Types\n\n### `SignatureFileType`\nEnum for supported save/export formats:\n- `'Png'` — PNG image format (default)\n- `'Jpeg'` — JPEG image format\n- `'Svg'` — SVG vector format\n\n**Usage:**\n```tsx\nimport { SignatureFileType } from '@syncfusion/ej2-react-inputs';\n\n// Use as a string literal or as the enum value\nsignature.save('Png', 'my-signature');\nsignature.save('Jpeg' as SignatureFileType, 'my-signature');\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6742,"content_sha256":"d3aee47cacd757881f821cf4b5b91bfbe0f9c4ae2c7caee64e01e9c749cd537f"},{"filename":"references/signature-customization.md","content":"# Customization in Syncfusion React Signature\n\n## Table of Contents\n- [Stroke Width](#stroke-width)\n- [Stroke Color](#stroke-color)\n- [Background Color](#background-color)\n- [Background Image](#background-image)\n\n---\n\n## Stroke Width\n\nControl stroke thickness using `maxStrokeWidth`, `minStrokeWidth`, and `velocity`. The component calculates a variable stroke width based on these three values to produce a natural, smooth signature.\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `maxStrokeWidth` | `number` | `2` | Maximum thickness of the stroke |\n| `minStrokeWidth` | `number` | `0.5` | Minimum thickness of the stroke |\n| `velocity` | `number` | `0.7` | Rate of stroke width change (0–1); lower values = greater width variation |\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv id=\"signature-control\">\n \u003ch4>Sign here\u003c/h4>\n \u003cSignatureComponent\n id=\"signature\"\n maxStrokeWidth={3}\n minStrokeWidth={0.5}\n velocity={0.7}\n />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Tip:** Increase `maxStrokeWidth` for bold strokes. Lower `velocity` produces more dramatic width variation between fast and slow strokes.\n\n---\n\n## Stroke Color\n\nUse `strokeColor` to set the pen/ink color. Accepts hex codes (`#000000`), RGB values (`rgb(0,0,0)`), or CSS color names (`red`). The default is `#000000` (black).\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function applyColor(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const color: string = (document.getElementById('colorInput') as HTMLInputElement).value;\n signature.strokeColor = color;\n }\n\n return (\n \u003cdiv>\n \u003cinput type=\"text\" id=\"colorInput\" placeholder=\"e.g. #e91e63 or red\" />\n \u003cButtonComponent isPrimary={true} onClick={applyColor}>Set Stroke Color\u003c/ButtonComponent>\n \u003cdiv id=\"signature-control\">\n \u003cSignatureComponent id=\"signature\" strokeColor=\"#000000\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Background Color\n\nUse `backgroundColor` to fill the canvas background. Accepts hex codes, RGB values, or CSS color names. The default is `''` (transparent/white).\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function applyBg(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const bgColor: string = (document.getElementById('bgInput') as HTMLInputElement).value;\n signature.backgroundColor = bgColor;\n }\n\n return (\n \u003cdiv>\n \u003cinput type=\"text\" id=\"bgInput\" placeholder=\"e.g. #f0f0f0 or lightyellow\" />\n \u003cButtonComponent isPrimary={true} onClick={applyBg}>Set Background Color\u003c/ButtonComponent>\n \u003cdiv id=\"signature-control\">\n \u003cSignatureComponent id=\"signature\" backgroundColor=\"#ffffff\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Note:** `backgroundColor` affects the visual appearance. Whether the background is included when saving is controlled by `saveWithBackground` (see open-save.md).\n\n---\n\n## Background Image\n\nUse `backgroundImage` to set a URL or base64-encoded image as the canvas background. The image fills the canvas behind the signature strokes.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function applyImage(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const url: string = (document.getElementById('imgInput') as HTMLInputElement).value;\n signature.backgroundImage = url;\n }\n\n return (\n \u003cdiv>\n \u003cinput type=\"text\" id=\"imgInput\" placeholder=\"Enter image URL or base64\" />\n \u003cButtonComponent isPrimary={true} onClick={applyImage}>Set Background Image\u003c/ButtonComponent>\n \u003cdiv id=\"signature-control\">\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Tip:** Hosted URLs and local base64 strings are both supported. Use a transparent background image for watermark or template effects.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4673,"content_sha256":"24b2f37764331b2c4b8fcd8d1cfeeebc907e1a64b264137e02b6f9ddee4dab35"},{"filename":"references/signature-getting-started.md","content":"# Getting Started with Syncfusion React Signature\n\nSet up a basic Signature component in a React application using Vite.\n\n---\n\n## Installation\n\n```bash\nnpm install @syncfusion/ej2-react-inputs --save\n```\n\nThe Signature component is part of the `@syncfusion/ej2-react-inputs` package.\n\n---\n\n## CSS Imports\n\nAdd the following theme imports to `src/App.css`:\n\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/signature/index.css\";\n```\n\nImport `App.css` in `src/App.tsx`:\n\n```tsx\nimport './App.css';\n```\n\n---\n\n## Basic Setup\n\nAdd the `SignatureComponent` to your application (`src/App.tsx`):\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cdiv id=\"signature-control\">\n \u003ch4>Sign here\u003c/h4>\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Running the Application\n\n```bash\nnpm run dev\n```\n\nThis starts the Vite development server. Open the URL shown in the terminal to see the Signature component rendered in the browser.\n\n---\n\n## Project Setup (Vite)\n\nCreate a new React + TypeScript project:\n\n```bash\nnpm create vite@latest my-app -- --template react-ts\ncd my-app\nnpm install @syncfusion/ej2-react-inputs --save\nnpm run dev\n```\n\nFor a JavaScript project:\n\n```bash\nnpm create vite@latest my-app -- --template react\ncd my-app\nnpm install @syncfusion/ej2-react-inputs --save\nnpm run dev\n```\n\n---\n\n## Notes\n\n- The component renders a `\u003ccanvas>` element and captures strokes via pointer/touch/mouse events.\n- No additional configuration is required for basic usage — `id` is the only required prop.\n- The component requires a wrapping element with a defined size for the canvas to render correctly in layouts.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1817,"content_sha256":"74b3d1fb856e1057aa171b613c3e893f8bf7e1b0040306f7306731e13015e4a4"},{"filename":"references/signature-open-save.md","content":"# Open and Save in Syncfusion React Signature\n\n## Table of Contents\n- [Open / Load Signature](#open--load-signature)\n- [Save as Base64](#save-as-base64)\n- [Save as Blob](#save-as-blob)\n- [Save as Image File](#save-as-image-file)\n- [Save with Background](#save-with-background)\n\n---\n\n## Open / Load Signature\n\nThe `load(signature, width?, height?)` method loads a previously saved signature onto the canvas. Accepts a base64 string or a hosted/online image URL in PNG, JPEG, or SVG format.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function loadSignature(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const value: string = (document.getElementById('signInput') as HTMLInputElement).value;\n signature.load(value);\n }\n\n return (\n \u003cdiv>\n \u003cinput type=\"text\" id=\"signInput\" placeholder=\"Enter base64 or URL of signature\" />\n \u003cButtonComponent isPrimary={true} onClick={loadSignature}>Open\u003c/ButtonComponent>\n \u003cdiv id=\"signature-control\">\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Parameters:**\n- `signature` (string) — base64 string or URL of the image\n- `width` (number, optional) — width to render the loaded image\n- `height` (number, optional) — height to render the loaded image\n\n---\n\n## Save as Base64\n\nThe `getSignature(type?)` method returns the current canvas content as a base64-encoded string. Supports `'Png'`, `'Jpeg'`, and `'Svg'` formats (default: `'Png'`).\n\nThe returned base64 string can be stored in a database or passed back to `load()` to restore the signature.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const [base64, setBase64] = React.useState\u003cstring>('');\n\n function getBase64(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const result: string = signature.getSignature();\n setBase64(result);\n console.log(result); // data:image/png;base64,...\n }\n\n return (\n \u003cdiv>\n \u003cSignatureComponent id=\"signature\" />\n \u003cButtonComponent cssClass=\"e-primary\" onClick={getBase64}>Save as Base64\u003c/ButtonComponent>\n {base64 && \u003cimg src={base64} alt=\"Saved signature\" style={{ border: '1px solid #ccc', marginTop: 8 }} />}\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Save as Blob\n\nTwo methods are available for blob output:\n\n- **`saveAsBlob()`** — Returns a `Blob` object directly from the current canvas content.\n- **`getBlob(url)`** — Converts a given base64/URL string to a `Blob` object.\n\nUse blobs for file uploads, form submissions, or binary storage.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function saveBlob(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const blob: Blob = signature.saveAsBlob();\n // Use blob for upload, FormData, etc.\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = 'signature.png';\n link.click();\n }\n\n return (\n \u003cdiv>\n \u003cSignatureComponent id=\"signature\" />\n \u003cButtonComponent cssClass=\"e-primary\" onClick={saveBlob}>Save as Blob\u003c/ButtonComponent>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Save as Image File\n\nThe `save(type?, fileName?)` method downloads the signature as an image file directly to the user's browser. Accepts `'Png'`, `'Jpeg'`, or `'Svg'` as the file type. The default is `'Png'`.\n\n```tsx\nimport { SignatureComponent, SignatureFileType } from '@syncfusion/ej2-react-inputs';\nimport { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';\nimport { MenuEventArgs } from '@syncfusion/ej2-react-splitbuttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const items = [{ text: 'Png' }, { text: 'Jpeg' }, { text: 'Svg' }];\n\n function onSelect(args: MenuEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.save(args.item.text as SignatureFileType, 'Signature');\n }\n\n return (\n \u003cdiv>\n \u003cdiv>\n \u003cSplitButtonComponent\n content=\"Save\"\n iconCss=\"e-sign-icons e-save\"\n items={items}\n select={onSelect}\n />\n \u003c/div>\n \u003cdiv id=\"signature-control\">\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Parameters:**\n- `type` (SignatureFileType, optional) — `'Png'` | `'Jpeg'` | `'Svg'`\n- `fileName` (string, optional) — name of the downloaded file (without extension)\n\n---\n\n## Save with Background\n\nThe `saveWithBackground` property controls whether the background color and background image are included when saving. The default is `true`.\n\n- `true` — background is included in the saved image\n- `false` — signature strokes only, on a transparent/white background\n\n```tsx\nimport { SignatureComponent, SignatureFileType } from '@syncfusion/ej2-react-inputs';\nimport { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';\nimport { MenuEventArgs } from '@syncfusion/ej2-react-splitbuttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const items = [{ text: 'Png' }, { text: 'Jpeg' }, { text: 'Svg' }];\n\n function onSelect(args: MenuEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.save(args.item.text as SignatureFileType, 'Signature');\n }\n\n return (\n \u003cdiv>\n \u003cSplitButtonComponent content=\"Save\" items={items} select={onSelect} />\n \u003cdiv id=\"signature-control\">\n {/* saveWithBackground={true} saves the purple background with the signature */}\n \u003cSignatureComponent\n id=\"signature\"\n backgroundColor=\"rgb(103 58 183)\"\n saveWithBackground={true}\n />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Tip:** Set `saveWithBackground={false}` when you need a transparent PNG for overlaying the signature on other documents.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6665,"content_sha256":"131e25f54a381d7a899537f6426a430dd1d2997f75263105c21d833aa05cc725"},{"filename":"references/signature-toolbar-integration.md","content":"# Toolbar Integration with Syncfusion React Signature\n\n## Table of Contents\n- [Overview](#overview)\n- [Required Packages](#required-packages)\n- [Wiring Undo, Redo, and Clear](#wiring-undo-redo-and-clear)\n- [Save Button Integration](#save-button-integration)\n- [Stroke Color Picker](#stroke-color-picker)\n- [Background Color Picker](#background-color-picker)\n- [Stroke Width Dropdown](#stroke-width-dropdown)\n- [Full Toolbar Example](#full-toolbar-example)\n\n---\n\n## Overview\n\nIntegrate `SignatureComponent` with `ToolbarComponent` to provide a rich editing interface. The Signature's `change` event drives toolbar button state — enabling/disabling undo, redo, clear, and save based on the current signature state.\n\n**Key pattern:**\n- Call `canUndo()`, `canRedo()`, and `isEmpty()` inside the `change` handler to update button states.\n- Use the toolbar's `clicked` event to dispatch actions to the Signature component.\n\n---\n\n## Required Packages\n\n```bash\nnpm install @syncfusion/ej2-react-inputs @syncfusion/ej2-react-navigations @syncfusion/ej2-react-buttons @syncfusion/ej2-react-splitbuttons @syncfusion/ej2-react-dropdowns --save\n```\n\n---\n\n## Wiring Undo, Redo, and Clear\n\nUse `tooltipText` on `ItemDirective` to identify toolbar button actions inside the `clicked` handler:\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ToolbarComponent, ItemsDirective, ItemDirective, ClickEventArgs } from '@syncfusion/ej2-react-navigations';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function onClicked(args: ClickEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n switch (args.item.tooltipText) {\n case 'Undo (Ctrl + Z)':\n if (signature.canUndo()) signature.undo();\n break;\n case 'Redo (Ctrl + Y)':\n if (signature.canRedo()) signature.redo();\n break;\n case 'Clear':\n signature.clear();\n break;\n }\n }\n\n return (\n \u003cdiv>\n \u003cToolbarComponent clicked={onClicked}>\n \u003cItemsDirective>\n \u003cItemDirective text=\"Undo\" prefixIcon=\"e-icons e-undo\" tooltipText=\"Undo (Ctrl + Z)\" />\n \u003cItemDirective text=\"Redo\" prefixIcon=\"e-icons e-redo\" tooltipText=\"Redo (Ctrl + Y)\" />\n \u003cItemDirective text=\"Clear\" prefixIcon=\"e-sign-icons e-clear\" tooltipText=\"Clear\" />\n \u003c/ItemsDirective>\n \u003c/ToolbarComponent>\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Save Button Integration\n\nUse a `SplitButtonComponent` inside a toolbar template to let users choose the save format (PNG, JPEG, SVG):\n\n```tsx\nimport { SignatureComponent, SignatureFileType } from '@syncfusion/ej2-react-inputs';\nimport { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';\nimport { MenuEventArgs } from '@syncfusion/ej2-react-splitbuttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const saveItems = [{ text: 'Png' }, { text: 'Jpeg' }, { text: 'Svg' }];\n\n function onSelect(args: MenuEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.save(args.item.text as SignatureFileType, 'Signature');\n }\n\n function saveTemplate() {\n return (\n \u003cSplitButtonComponent\n content=\"Save\"\n id=\"save-option\"\n iconCss=\"e-sign-icons e-save\"\n items={saveItems}\n select={onSelect}\n disabled={true}\n />\n );\n }\n\n return (\n \u003cdiv>\n {saveTemplate()}\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\nEnable the save button by calling `saveBtn.disabled = false` inside the `change` handler when `!signature.isEmpty()`.\n\n---\n\n## Stroke Color Picker\n\nUse `ColorPickerComponent` in a toolbar template to let users change the stroke color dynamically:\n\n```tsx\nimport { ColorPickerComponent, ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const strokePresets = {\n custom: ['#000000', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4',\n '#00bcd4', '#009688', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107']\n };\n\n function onStrokeColorChanged(args: ColorPickerEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n if (!signature.disabled) {\n signature.strokeColor = args.currentValue.rgba;\n }\n }\n\n return (\n \u003cdiv>\n \u003cColorPickerComponent\n id=\"stroke-color\"\n mode=\"Palette\"\n modeSwitcher={false}\n showButtons={false}\n columns={4}\n presetColors={strokePresets}\n change={onStrokeColorChanged}\n />\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Background Color Picker\n\nUse a second `ColorPickerComponent` to change the canvas background color:\n\n```tsx\nimport { ColorPickerComponent, ColorPickerEventArgs, SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const bgPresets = {\n custom: ['#ffffff', '#f44336', '#e91e63', '#9c27b0', '#673ab7', '#2196f3',\n '#03a9f4', '#00bcd4', '#009688', '#8bc34a', '#cddc39', '#ffeb3b']\n };\n\n function onBgColorChanged(args: ColorPickerEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n if (!signature.disabled) {\n signature.backgroundColor = args.currentValue.rgba;\n }\n }\n\n return (\n \u003cdiv>\n \u003cColorPickerComponent\n id=\"bg-color\"\n noColor={true}\n mode=\"Palette\"\n modeSwitcher={false}\n showButtons={false}\n columns={4}\n presetColors={bgPresets}\n change={onBgColorChanged}\n />\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Stroke Width Dropdown\n\nUse a `DropDownListComponent` to let users select the maximum stroke width:\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const widthData: number[] = [1, 2, 3, 4, 5];\n\n function onWidthChanged(args: any): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.maxStrokeWidth = args.value;\n }\n\n return (\n \u003cdiv>\n \u003cDropDownListComponent\n id=\"stroke-width-ddl\"\n dataSource={widthData}\n value={2}\n width=\"60\"\n change={onWidthChanged}\n />\n \u003cSignatureComponent id=\"signature\" maxStrokeWidth={2} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Full Toolbar Example\n\nComplete integration using `ToolbarComponent` with undo, redo, save (split button), stroke color picker, background color picker, stroke width dropdown, clear, and a disabled toggle:\n\n```tsx\nimport * as React from 'react';\nimport { SignatureComponent, SignatureFileType, ColorPickerComponent, ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { ToolbarComponent, ItemsDirective, ItemDirective, ClickEventArgs } from '@syncfusion/ej2-react-navigations';\nimport { SplitButtonComponent, MenuEventArgs } from '@syncfusion/ej2-react-splitbuttons';\nimport { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';\nimport { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport { ChangeEventArgs } from '@syncfusion/ej2-buttons';\n\nfunction App() {\n const saveItems = [{ text: 'Png' }, { text: 'Jpeg' }, { text: 'Svg' }];\n const widthData = [1, 2, 3, 4, 5];\n const strokePresets = { custom: ['#000000','#e91e63','#9c27b0','#673ab7','#2196f3','#03a9f4','#00bcd4','#009688','#8bc34a','#cddc39','#ffeb3b','#ffc107'] };\n const bgPresets = { custom: ['#ffffff','#f44336','#e91e63','#9c27b0','#673ab7','#2196f3','#03a9f4','#00bcd4','#009688','#8bc34a','#cddc39','#ffeb3b'] };\n\n function onClicked(args: ClickEventArgs): void {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n if (sig.disabled && args.item.tooltipText !== 'Disabled') return;\n switch (args.item.tooltipText) {\n case 'Undo (Ctrl + Z)': if (sig.canUndo()) sig.undo(); break;\n case 'Redo (Ctrl + Y)': if (sig.canRedo()) sig.redo(); break;\n case 'Clear': sig.clear(); break;\n }\n }\n\n function onChange(): void {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n // Update undo/redo/clear/save button states based on sig.canUndo(), sig.canRedo(), sig.isEmpty()\n }\n\n function onDisabledChange(args: ChangeEventArgs): void {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n sig.disabled = args.checked;\n }\n\n function saveTemplate() {\n return (\n \u003cSplitButtonComponent content=\"Save\" id=\"save-option\" iconCss=\"e-sign-icons e-save\" items={saveItems}\n select={(args: MenuEventArgs) => {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n sig.save(args.item.text as SignatureFileType, 'Signature');\n }} disabled={true} />\n );\n }\n\n function strokeColorTemplate() {\n return (\n \u003cColorPickerComponent id=\"stroke-color\" mode=\"Palette\" modeSwitcher={false} showButtons={false}\n columns={4} presetColors={strokePresets}\n change={(args: ColorPickerEventArgs) => {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n if (!sig.disabled) sig.strokeColor = args.currentValue.rgba;\n }} />\n );\n }\n\n function bgColorTemplate() {\n return (\n \u003cColorPickerComponent id=\"bg-color\" noColor={true} mode=\"Palette\" modeSwitcher={false} showButtons={false}\n columns={4} presetColors={bgPresets}\n change={(args: ColorPickerEventArgs) => {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n if (!sig.disabled) sig.backgroundColor = args.currentValue.rgba;\n }} />\n );\n }\n\n function strokeWidthTemplate() {\n return (\n \u003cDropDownListComponent id=\"stroke-width-ddl\" dataSource={widthData} value={2} width=\"60\"\n change={(args: any) => {\n const sig: any = getComponent(document.getElementById('signature'), 'signature');\n sig.maxStrokeWidth = args.value;\n }} />\n );\n }\n\n return (\n \u003cdiv>\n \u003cToolbarComponent id=\"toolbar\" clicked={onClicked}>\n \u003cItemsDirective>\n \u003cItemDirective text=\"Undo\" prefixIcon=\"e-icons e-undo\" tooltipText=\"Undo (Ctrl + Z)\" />\n \u003cItemDirective text=\"Redo\" prefixIcon=\"e-icons e-redo\" tooltipText=\"Redo (Ctrl + Y)\" />\n \u003cItemDirective type=\"Separator\" />\n \u003cItemDirective tooltipText=\"Save (Ctrl + S)\" type=\"Button\" template={saveTemplate} />\n \u003cItemDirective type=\"Separator\" />\n \u003cItemDirective tooltipText=\"Stroke Color\" template={strokeColorTemplate} />\n \u003cItemDirective type=\"Separator\" />\n \u003cItemDirective tooltipText=\"Background Color\" template={bgColorTemplate} />\n \u003cItemDirective type=\"Separator\" />\n \u003cItemDirective tooltipText=\"Stroke Width\" template={strokeWidthTemplate} />\n \u003cItemDirective type=\"Separator\" />\n \u003cItemDirective text=\"Clear\" prefixIcon=\"e-sign-icons e-clear\" tooltipText=\"Clear\" />\n \u003cItemDirective tooltipText=\"Disabled\" type=\"Input\"\n template={\u003cCheckBoxComponent label=\"Disabled\" change={onDisabledChange} />} align=\"Right\" />\n \u003c/ItemsDirective>\n \u003c/ToolbarComponent>\n \u003cSignatureComponent id=\"signature\" maxStrokeWidth={2} change={onChange} />\n \u003c/div>\n );\n}\nexport default App;\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12059,"content_sha256":"35b858f8d818807c0268498542673fa234daa23f88dacf775b8fdfeefa877f5c"},{"filename":"references/signature-user-interaction.md","content":"# User Interaction in Syncfusion React Signature\n\n## Table of Contents\n- [Undo and Redo](#undo-and-redo)\n- [Clear](#clear)\n- [Disabled](#disabled)\n- [ReadOnly](#readonly)\n- [Draw Text as Signature](#draw-text-as-signature)\n- [Keyboard Shortcuts](#keyboard-shortcuts)\n- [Change Event](#change-event)\n\n---\n\n## Undo and Redo\n\nThe Signature component maintains a snapshot history of every drawing action. Use `undo()` and `redo()` to navigate this history, and `canUndo()` / `canRedo()` to check availability before calling them.\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `undo()` | `void` | Reverts the last stroke/action |\n| `redo()` | `void` | Re-applies the last undone action |\n| `canUndo()` | `boolean` | `true` if undo history is available |\n| `canRedo()` | `boolean` | `true` if redo history is available |\n\n```tsx\nimport { SignatureComponent, SignatureChangeEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n const sigRef = React.useRef\u003cSignatureComponent>(null);\n const [undoEnabled, setUndoEnabled] = React.useState(false);\n const [redoEnabled, setRedoEnabled] = React.useState(false);\n\n function handleChange(args: SignatureChangeEventArgs) {\n if (sigRef.current) {\n setUndoEnabled(sigRef.current.canUndo());\n setRedoEnabled(sigRef.current.canRedo());\n }\n }\n\n return (\n \u003cdiv>\n \u003cButtonComponent disabled={!undoEnabled} onClick={() => sigRef.current?.undo()}>Undo\u003c/ButtonComponent>\n \u003cButtonComponent disabled={!redoEnabled} onClick={() => sigRef.current?.redo()}>Redo\u003c/ButtonComponent>\n \u003cSignatureComponent id=\"signature\" ref={sigRef} change={handleChange} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Clear\n\nThe `clear()` method erases all strokes from the canvas. This action is added to the undo history, so the user can undo a clear operation. Use `isEmpty()` to check if the canvas is already empty.\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `clear()` | `void` | Clears all strokes from the canvas |\n| `isEmpty()` | `boolean` | `true` if the canvas has no strokes |\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n const sigRef = React.useRef\u003cSignatureComponent>(null);\n\n function handleClear(): void {\n if (sigRef.current && !sigRef.current.isEmpty()) {\n sigRef.current.clear();\n }\n }\n\n return (\n \u003cdiv>\n \u003cButtonComponent onClick={handleClear}>Clear\u003c/ButtonComponent>\n \u003cSignatureComponent id=\"signature\" ref={sigRef} />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Disabled\n\nSet `disabled={true}` to prevent any interaction with the component. The canvas appears with reduced opacity to indicate the disabled state. The component cannot receive focus while disabled.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport { ChangeEventArgs } from '@syncfusion/ej2-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function onDisableChange(args: ChangeEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.disabled = args.checked;\n }\n\n return (\n \u003cdiv>\n \u003cCheckBoxComponent label=\"Disabled\" change={onDisableChange} />\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## ReadOnly\n\nSet `isReadOnly={true}` to prevent drawing while still allowing the component to receive focus. Useful for displaying a previously captured signature without allowing modification.\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport { ChangeEventArgs } from '@syncfusion/ej2-buttons';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n function onReadOnlyChange(args: ChangeEventArgs): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n signature.isReadOnly = args.checked;\n }\n\n return (\n \u003cdiv>\n \u003cCheckBoxComponent label=\"ReadOnly\" change={onReadOnlyChange} />\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n**Difference from `disabled`:**\n- `disabled` — component cannot receive focus; full interaction blocked\n- `isReadOnly` — component can receive focus; only drawing is blocked\n\n---\n\n## Draw Text as Signature\n\nThe `draw(text, fontFamily?, fontSize?)` method renders a text string onto the canvas as a signature. Useful for auto-generating a typed signature.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `text` | `string` | — | Text to render on the canvas |\n| `fontFamily` | `string` | `'Arial'` | Font family (e.g., `'Serif'`, `'Cursive'`) |\n| `fontSize` | `number` | `30` | Font size in pixels |\n\n```tsx\nimport { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';\nimport { getComponent } from '@syncfusion/ej2-base';\nimport * as React from 'react';\n\nfunction App() {\n const fontData: string[] = ['Arial', 'Serif', 'Sans-serif', 'Cursive', 'Fantasy'];\n const sizeData: number[] = [20, 30, 40, 50];\n\n function drawText(): void {\n const signature: any = getComponent(document.getElementById('signature'), 'signature');\n const text: string = (document.getElementById('textInput') as HTMLInputElement).value;\n const font: string = (document.getElementById('fontDDL') as any).value;\n const size: number = (document.getElementById('sizeDDL') as any).value;\n signature.draw(text, font, size);\n }\n\n return (\n \u003cdiv>\n \u003cdiv>\n \u003clabel>Text: \u003c/label>\n \u003cinput type=\"text\" id=\"textInput\" placeholder=\"Enter your name\" />\n \u003c/div>\n \u003cdiv>\n \u003clabel>Font: \u003c/label>\n \u003cDropDownListComponent id=\"fontDDL\" dataSource={fontData} value=\"Arial\" />\n \u003c/div>\n \u003cdiv>\n \u003clabel>Size: \u003c/label>\n \u003cDropDownListComponent id=\"sizeDDL\" dataSource={sizeData} value={30} />\n \u003c/div>\n \u003cButtonComponent isPrimary={true} onClick={drawText}>Draw\u003c/ButtonComponent>\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;\n```\n\n---\n\n## Keyboard Shortcuts\n\nThe Signature component supports built-in keyboard shortcuts when the canvas has focus:\n\n| Key | Action |\n|-----|--------|\n| `Ctrl + Z` | Undo the last action |\n| `Ctrl + Y` | Redo the last action |\n| `Ctrl + S` | Save the signature (triggers `beforeSave` event) |\n| `Delete` | Clear all signature strokes |\n\nThe `beforeSave` event is raised for keyboard-triggered saves (`Ctrl + S`), allowing customization of the file name and type before saving.\n\n---\n\n## Change Event\n\nThe `change` event fires after every user action — completing a stroke, undo, redo, and clear. Use it to update UI controls (e.g., enable/disable undo/redo/clear buttons).\n\n```tsx\nimport { SignatureComponent, SignatureChangeEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n function handleChange(args: SignatureChangeEventArgs): void {\n // Called after each stroke, undo, redo, or clear\n console.log('Signature changed', args);\n }\n\n return (\n \u003cSignatureComponent id=\"signature\" change={handleChange} />\n );\n}\nexport default App;\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7731,"content_sha256":"a7355e97977f9cf776ff395ef3f4aeb95fae123c93d41e028b5e31d4c9f3e3bc"},{"filename":"references/textarea-adornments.md","content":"# Adornments in React TextArea Component\n\n## Table of Contents\n- [Overview](#overview)\n- [Adding Adornments](#adding-adornments)\n- [Adornment Flow](#adornment-flow)\n- [Adornment Orientation](#adornment-orientation)\n- [Common Use Cases](#common-use-cases)\n- [Advanced Examples](#advanced-examples)\n\n## Overview\n\nAdornments enable custom elements (icons, text labels, buttons, or complex HTML) to be added before or after the TextArea. Using `prependTemplate` and `appendTemplate` properties, combined with `adornmentFlow` and `adornmentOrientation`, you can create flexible, visually rich layouts.\n\n**Common Use Cases:**\n- Visual context indicators (edit icons, status icons)\n- Formatting tools (bold, italic, underline buttons)\n- Action buttons (send, save, clear)\n- Character count displays\n- Validation status icons\n\n## Adding Adornments\n\n### Prepend Template (Before TextArea)\n\nAdd custom HTML or JSX content before the TextArea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const prependIcon = () => (\n \u003cspan className='prepend-icon'>📝\u003c/span>\n );\n\n return (\n \u003cTextAreaComponent \n id='textarea'\n placeholder='Enter your message'\n prependTemplate={prependIcon}\n />\n );\n}\n\nexport default App;\n```\n\n### Append Template (After TextArea)\n\nAdd custom content after the TextArea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const appendButton = () => (\n \u003cbutton className='send-btn'>Send\u003c/button>\n );\n\n return (\n \u003cTextAreaComponent \n id='message'\n placeholder='Type your message'\n appendTemplate={appendButton}\n />\n );\n}\n\nexport default App;\n```\n\n### Both Prepend and Append\n\nCombine prepend and append templates:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const prependContent = () => (\n \u003cspan className='icon'>✏️\u003c/span>\n );\n\n const appendContent = () => (\n \u003cdiv>\n \u003cbutton className='clear-btn'>Clear\u003c/button>\n \u003cbutton className='submit-btn'>Submit\u003c/button>\n \u003c/div>\n );\n\n return (\n \u003cTextAreaComponent \n id='form-textarea'\n placeholder='Enter feedback'\n prependTemplate={prependContent}\n appendTemplate={appendContent}\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n## Adornment Flow\n\nThe `adornmentFlow` property defines where adornments appear around the TextArea.\n\n### Horizontal Flow\n\nPrepend appears on the left, append appears on the right.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const prependContent = () => \u003cspan>Icon\u003c/span>;\n const appendContent = () => \u003cbutton>Action\u003c/button>;\n\n return (\n \u003cTextAreaComponent \n id='textarea'\n prependTemplate={prependContent}\n appendTemplate={appendContent}\n adornmentFlow='Horizontal'\n placeholder='Message'\n />\n );\n}\n\nexport default App;\n```\n\n**Layout:**\n```\n┌─────────────────────────────────────────┐\n│ Icon │ TextArea Content │ Action│\n└─────────────────────────────────────────┘\n```\n\n### Vertical Flow\n\nPrepend appears above, append appears below.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const prependContent = () => \u003cspan>📋\u003c/span>;\n const appendContent = () => \u003cbutton>Send\u003c/button>;\n\n return (\n \u003cTextAreaComponent \n id='textarea'\n prependTemplate={prependContent}\n appendTemplate={appendContent}\n adornmentFlow='Vertical'\n placeholder='Message'\n />\n );\n}\n\nexport default App;\n```\n\n**Layout:**\n```\n┌──────────────────────────────┐\n│ 📋 │\n├──────────────────────────────┤\n│ TextArea Content │\n├──────────────────────────────┤\n│ Send Button │\n└──────────────────────────────┘\n```\n\n## Adornment Orientation\n\nThe `adornmentOrientation` property controls how items are arranged within each adornment section.\n\n### Horizontal Orientation\n\nItems are displayed in a row:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const appendContent = () => (\n \u003cdiv className='button-group'>\n \u003cbutton>Bold\u003c/button>\n \u003cbutton>Italic\u003c/button>\n \u003cbutton>Underline\u003c/button>\n \u003c/div>\n );\n\n return (\n \u003cTextAreaComponent \n id='editor'\n appendTemplate={appendContent}\n adornmentOrientation='Horizontal'\n placeholder='Edit text here'\n />\n );\n}\n\nexport default App;\n```\n\n**Layout:**\n```\nTextArea Content | [Bold] [Italic] [Underline]\n```\n\n### Vertical Orientation\n\nItems are displayed in a column:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const appendContent = () => (\n \u003cdiv className='toolbar'>\n \u003cbutton>✓ Save\u003c/button>\n \u003cbutton>⟲ Redo\u003c/button>\n \u003cbutton>↶ Undo\u003c/button>\n \u003c/div>\n );\n\n return (\n \u003cTextAreaComponent \n id='document'\n appendTemplate={appendContent}\n adornmentOrientation='Vertical'\n placeholder='Document content'\n />\n );\n}\n\nexport default App;\n```\n\n**Layout:**\n```\n┌─────────────────────────────┬─────────┐\n│ TextArea Content │ ✓ Save │\n│ ├─────────┤\n│ │ ⟲ Redo │\n│ ├─────────┤\n│ │ ↶ Undo │\n└─────────────────────────────┴─────────┘\n```\n\n## Common Use Cases\n\n### Character Count Display\n\nShow remaining characters as append content:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n const maxChars = 500;\n\n const appendContent = () => (\n \u003cdiv className='char-count'>\n {charCount} / {maxChars}\n \u003c/div>\n );\n\n return (\n \u003cTextAreaComponent \n id='feedback'\n maxLength={maxChars}\n appendTemplate={appendContent}\n input={(args) => setCharCount((args.value || '').length)}\n placeholder='Your feedback'\n />\n );\n}\n\nexport default App;\n```\n\n### Validation Status Icon\n\nShow success/error status:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isValid, setIsValid] = useState(false);\n\n const appendContent = () => (\n \u003cspan className={isValid ? 'icon-success' : 'icon-error'}>\n {isValid ? '✓' : '✗'}\n \u003c/span>\n );\n\n const handleChange = (args) => {\n setIsValid((args.value || '').length > 0);\n };\n\n return (\n \u003cTextAreaComponent \n id='message'\n appendTemplate={appendContent}\n change={handleChange}\n placeholder='Enter message'\n />\n );\n}\n\nexport default App;\n```\n\n### Formatting Toolbar\n\nAdd text formatting options:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef(null);\n\n const appendContent = () => (\n \u003cdiv className='toolbar'>\n \u003cbutton onClick={() => insertFormat('**', '**')}>Bold\u003c/button>\n \u003cbutton onClick={() => insertFormat('*', '*')}>Italic\u003c/button>\n \u003cbutton onClick={() => insertFormat('~~', '~~')}>Strike\u003c/button>\n \u003c/div>\n );\n\n const insertFormat = (before, after) => {\n if (textareaRef.current) {\n const textarea = textareaRef.current;\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const text = textarea.value;\n const selectedText = text.substring(start, end);\n const newText = \n text.substring(0, start) + \n before + selectedText + after + \n text.substring(end);\n textarea.value = newText;\n }\n };\n\n return (\n \u003cTextAreaComponent \n ref={textareaRef}\n id='editor'\n appendTemplate={appendContent}\n placeholder='Write here'\n />\n );\n}\n\nexport default App;\n```\n\n### Action Buttons\n\nAdd multiple action buttons:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const appendContent = () => (\n \u003cdiv className='actions'>\n \u003cbutton onClick={() => setText('')}>Clear\u003c/button>\n \u003cbutton onClick={() => handleSubmit()}>Send\u003c/button>\n \u003c/div>\n );\n\n const handleSubmit = () => {\n console.log('Submitted:', text);\n setText('');\n };\n\n return (\n \u003cTextAreaComponent \n id='message'\n value={text}\n input={(args) => setText(args.value || '')}\n appendTemplate={appendContent}\n placeholder='Your message'\n />\n );\n}\n\nexport default App;\n```\n\n## Advanced Examples\n\n### Multi-Row Layout with Both Adornments\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const prependContent = () => (\n \u003cdiv className='left-icons'>\n \u003cspan title='Edit'>✏️\u003c/span>\n \u003cspan title='Attachments'>📎\u003c/span>\n \u003c/div>\n );\n\n const appendContent = () => (\n \u003cdiv className='right-actions'>\n \u003cbutton className='action-btn'>Preview\u003c/button>\n \u003cbutton className='action-btn'>Submit\u003c/button>\n \u003cbutton className='action-btn'>Save\u003c/button>\n \u003c/div>\n );\n\n return (\n \u003cTextAreaComponent \n id='rich-text'\n prependTemplate={prependContent}\n appendTemplate={appendContent}\n adornmentFlow='Vertical'\n adornmentOrientation='Horizontal'\n placeholder='Create your content'\n rows={8}\n />\n );\n}\n\nexport default App;\n```\n\n### Contextual Adornments\n\nDynamically show/hide adornments based on state:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isFocused, setIsFocused] = useState(false);\n const [text, setText] = useState('');\n\n const appendContent = () => (\n isFocused && text.length > 0 && (\n \u003cbutton onClick={() => setText('')}>Clear\u003c/button>\n )\n );\n\n return (\n \u003cTextAreaComponent \n id='conditional'\n value={text}\n input={(args) => setText(args.value || '')}\n focus={() => setIsFocused(true)}\n blur={() => setIsFocused(false)}\n appendTemplate={appendContent}\n placeholder='Start typing...'\n />\n );\n}\n\nexport default App;\n```\n\n## Best Practices\n\n- Keep adornments lightweight - avoid complex components\n- Use meaningful icons and labels for clarity\n- Position actions logically (submit/send on right/bottom)\n- Test readability with different TextArea sizes\n- Ensure adornments don't interfere with keyboard navigation\n- Use horizontal flow for space efficiency in narrow layouts\n- Use vertical flow for better organization in complex forms\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12113,"content_sha256":"196edb91040c7e1aea40aff2e2eadfb3873928f5404816a727bc850eea251085"},{"filename":"references/textarea-api.md","content":"# Complete API Reference for React TextArea Component\n\n## Table of Contents\n- [Properties](#properties)\n- [Methods](#methods)\n- [Events](#events)\n- [Type Definitions](#type-definitions)\n- [Usage Examples](#usage-examples)\n\n## Properties\n\n### value\n\nSets or gets the content of the TextArea.\n\n```typescript\n\u003cTextAreaComponent value='Initial content' />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `value` | string | null | TextArea content |\n\n### placeholder\n\nSets the hint text displayed inside the TextArea when it's empty.\n\n```typescript\n\u003cTextAreaComponent placeholder='Enter your feedback' />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `placeholder` | string | null | Placeholder text |\n\n### rows\n\nSets the visible height of the TextArea, measured in lines.\n\n```typescript\n\u003cTextAreaComponent rows={5} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `rows` | number | undefined | Number of visible lines |\n\n### cols\n\nSets the visible width of the TextArea, measured in average character widths.\n\n```typescript\n\u003cTextAreaComponent cols={50} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `cols` | number | undefined | Number of character widths |\n\n### maxLength\n\nSpecifies the maximum number of characters allowed in the TextArea.\n\n```typescript\n\u003cTextAreaComponent maxLength={500} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `maxLength` | number | undefined | Maximum character limit |\n\n**Behavior:**\n- Input is prevented when limit is reached\n- Paste content is truncated to fit\n- Existing content can be edited freely\n\n### enabled\n\nSpecifies whether the TextArea is enabled for user interaction.\n\n```typescript\n\u003cTextAreaComponent enabled={false} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `enabled` | boolean | true | Enable/disable interaction |\n\n**When false:**\n- Appears grayed out\n- No user input allowed\n- Cannot receive focus\n\n### readonly\n\nSpecifies whether the TextArea is in read-only mode. Users can select and copy but not edit.\n\n```typescript\n\u003cTextAreaComponent readonly={true} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `readonly` | boolean | false | Read-only mode |\n\n**When true:**\n- Content cannot be modified\n- Content can be selected and copied\n- Can receive focus\n\n### floatLabelType\n\nSpecifies the floating label behavior for the placeholder text.\n\n```typescript\n\u003cTextAreaComponent floatLabelType='Auto' />\n```\n\n| Value | Behavior |\n|-------|----------|\n| `Never` | Placeholder never floats (default) |\n| `Auto` | Placeholder floats on focus or input |\n| `Always` | Placeholder always floats |\n\n### resizeMode\n\nSpecifies how the TextArea can be resized by the user.\n\n```typescript\n\u003cTextAreaComponent resizeMode='Both' />\n```\n\n| Value | Behavior |\n|-------|----------|\n| `Both` | User can resize both dimensions (default) |\n| `Vertical` | User can only resize height |\n| `Horizontal` | User can only resize width |\n| `None` | Resizing disabled |\n\n### width\n\nSets the width of the TextArea component.\n\n```typescript\n\u003cTextAreaComponent width='400px' />\n\u003cTextAreaComponent width='100%' />\n```\n\n| Type | Example |\n|------|---------|\n| `number` | `400` (pixels) |\n| `string` | `'400px'`, `'100%'` |\n\n### cssClass\n\nAdds custom CSS classes to the TextArea for custom styling.\n\n```typescript\n\u003cTextAreaComponent cssClass='e-outline e-small custom-style' />\n```\n\n**Built-in Classes:**\n- `e-small` - Smaller size\n- `e-bigger` - Larger size\n- `e-outline` - Outline mode\n- `e-filled` - Filled mode\n- `e-success` - Success validation state\n- `e-warning` - Warning validation state\n- `e-error` - Error validation state\n\n### showClearButton\n\nShows a button to clear the TextArea content.\n\n```typescript\n\u003cTextAreaComponent showClearButton={true} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `showClearButton` | boolean | false | Display clear button |\n\n### prependTemplate\n\nHTML template or JSX element to prepend before the TextArea.\n\n```typescript\n\u003cTextAreaComponent \n prependTemplate={() => \u003cspan className='icon'>📝\u003c/span>}\n/>\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `prependTemplate` | string \\| function \\| JSX.Element | null | Prepend content |\n\n### appendTemplate\n\nHTML template or JSX element to append after the TextArea.\n\n```typescript\n\u003cTextAreaComponent \n appendTemplate={() => \u003cbutton>Send\u003c/button>}\n/>\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `appendTemplate` | string \\| function \\| JSX.Element | null | Append content |\n\n### adornmentFlow\n\nControls where adornments (prepend/append) appear around the TextArea.\n\n```typescript\n\u003cTextAreaComponent adornmentFlow='Horizontal' />\n```\n\n| Value | Behavior |\n|-------|----------|\n| `Horizontal` | Prepend on left, append on right |\n| `Vertical` | Prepend above, append below |\n\n### adornmentOrientation\n\nControls how items are arranged within each adornment section.\n\n```typescript\n\u003cTextAreaComponent adornmentOrientation='Horizontal' />\n```\n\n| Value | Behavior |\n|-------|----------|\n| `Horizontal` | Items in a row |\n| `Vertical` | Items in a column |\n\n### enablePersistence\n\nEnables or disables persisting TextArea state across sessions.\n\n```typescript\n\u003cTextAreaComponent enablePersistence={true} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `enablePersistence` | boolean | false | Persist state |\n\n**When true:**\n- Component state saved to browser storage\n- State restored on page reload\n\n### enableRtl\n\nEnables or disables right-to-left rendering direction.\n\n```typescript\n\u003cTextAreaComponent enableRtl={true} />\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `enableRtl` | boolean | false | Right-to-left direction |\n\n### locale\n\nSets the culture/language for the TextArea component.\n\n```typescript\n\u003cTextAreaComponent locale='de-DE' />\n```\n\n| Common Locales |\n|---|\n| `en-US` (English, USA) |\n| `de-DE` (German) |\n| `fr-FR` (French) |\n| `es-ES` (Spanish) |\n| `ja-JP` (Japanese) |\n\n### htmlAttributes\n\nAdds additional HTML attributes to the TextArea element.\n\n```typescript\n\u003cTextAreaComponent \n htmlAttributes={{\n 'data-testid': 'feedback-field',\n 'aria-label': 'User feedback'\n }}\n/>\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `htmlAttributes` | { [key: string]: string } | {} | Custom HTML attributes |\n\n---\n\n## Methods\n\n### focusIn()\n\nSets focus to the TextArea, enabling keyboard interaction.\n\n```typescript\ntextareaRef.current?.focusIn();\n```\n\n**Returns:** void\n\n**Example:**\n```typescript\nconst handleFocus = () => {\n textareaRef.current?.focusIn();\n};\n```\n\n### focusOut()\n\nRemoves focus from the TextArea.\n\n```typescript\ntextareaRef.current?.focusOut();\n```\n\n**Returns:** void\n\n**Example:**\n```typescript\nconst handleBlur = () => {\n textareaRef.current?.focusOut();\n};\n```\n\n### getPersistData()\n\nRetrieves properties needed for persistence state.\n\n```typescript\nconst persistData = textareaRef.current?.getPersistData();\n```\n\n**Returns:** string\n\n**Example:**\n```typescript\nconst saveState = () => {\n const data = textareaRef.current?.getPersistData();\n localStorage.setItem('textareaState', data || '');\n};\n```\n\n### addAttributes()\n\nAdds multiple HTML attributes to the TextArea element dynamically.\n\n```typescript\ntextareaRef.current?.addAttributes({\n 'data-testid': 'textarea',\n 'aria-label': 'Feedback'\n});\n```\n\n**Parameters:**\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `attributes` | { [key: string]: string } | Attributes to add |\n\n**Returns:** void\n\n**Example:**\n```typescript\nconst addAccessibility = () => {\n textareaRef.current?.addAttributes({\n 'aria-required': 'true',\n 'aria-describedby': 'help-text',\n 'role': 'textbox'\n });\n};\n```\n\n### removeAttributes()\n\nRemoves multiple HTML attributes from the TextArea element.\n\n```typescript\ntextareaRef.current?.removeAttributes(['data-testid', 'aria-label']);\n```\n\n**Parameters:**\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `attributes` | string[] | Attribute names to remove |\n\n**Returns:** void\n\n**Example:**\n```typescript\nconst removeAttrs = () => {\n textareaRef.current?.removeAttributes([\n 'data-validation',\n 'title'\n ]);\n};\n```\n\n### destroy()\n\nRemoves the component from the DOM and detaches all event handlers. Maintains the original textarea element.\n\n```typescript\ntextareaRef.current?.destroy();\n```\n\n**Returns:** void\n\n**Example:**\n```typescript\nuseEffect(() => {\n return () => {\n textareaRef.current?.destroy();\n };\n}, []);\n```\n\n---\n\n## Events\n\n### created\n\nFired when the TextArea component is created and initialized.\n\n```typescript\n\u003cTextAreaComponent created={() => console.log('Created')} />\n```\n\n**Type:** EmitType\u003cObject>\n\n**Use Cases:**\n- Initialize related UI elements\n- Set initial focus\n- Load data\n\n### input\n\nFired every time the user types or modifies the TextArea value.\n\n```typescript\n\u003cTextAreaComponent \n input={(args: InputEventArgs) => console.log(args.value)}\n/>\n```\n\n**Type:** EmitType\u003cInputEventArgs>\n\n**Args:**\n```typescript\ninterface InputEventArgs {\n value: string; // Current textarea value\n keyCode: number; // Keyboard key code\n isComposed: boolean; // Composition event flag\n}\n```\n\n**Use Cases:**\n- Real-time character counting\n- Auto-save\n- Input validation\n\n### change\n\nFired when the content changes and focus is lost.\n\n```typescript\n\u003cTextAreaComponent \n change={(args: ChangedEventArgs) => console.log(args.value)}\n/>\n```\n\n**Type:** EmitType\u003cChangedEventArgs>\n\n**Args:**\n```typescript\ninterface ChangedEventArgs {\n value: string; // New textarea value\n isInteracted: boolean; // User-initiated change\n previousValue: string; // Previous value\n}\n```\n\n**Use Cases:**\n- Form submission\n- Database save\n- Validation after editing\n\n### focus\n\nFired when the TextArea gains focus.\n\n```typescript\n\u003cTextAreaComponent \n focus={(args: FocusInEventArgs) => console.log('Focused')}\n/>\n```\n\n**Type:** EmitType\u003cFocusInEventArgs>\n\n**Args:**\n```typescript\ninterface FocusInEventArgs {\n value: string; // Current textarea value\n}\n```\n\n**Use Cases:**\n- Show help text\n- Highlight related fields\n- Analytics logging\n\n### blur\n\nFired when focus is lost.\n\n```typescript\n\u003cTextAreaComponent \n blur={(args: FocusOutEventArgs) => console.log('Blurred')}\n/>\n```\n\n**Type:** EmitType\u003cFocusOutEventArgs>\n\n**Args:**\n```typescript\ninterface FocusOutEventArgs {\n value: string; // Current textarea value\n}\n```\n\n**Use Cases:**\n- Validation\n- Trim whitespace\n- Format content\n\n### destroyed\n\nFired when the TextArea component is destroyed.\n\n```typescript\n\u003cTextAreaComponent \n destroyed={() => console.log('Destroyed')}\n/>\n```\n\n**Type:** EmitType\u003cObject>\n\n**Use Cases:**\n- Cleanup event listeners\n- Clear timers\n- Save final state\n\n---\n\n## Type Definitions\n\n### AdornmentsDirection\n\n```typescript\ntype AdornmentsDirection = 'Horizontal' | 'Vertical';\n```\n\nUsed for `adornmentFlow` and `adornmentOrientation` properties.\n\n### FloatLabelType\n\n```typescript\ntype FloatLabelType = 'Never' | 'Auto' | 'Always';\n```\n\nUsed for `floatLabelType` property.\n\n### Resize\n\n```typescript\ntype Resize = 'Both' | 'Vertical' | 'Horizontal' | 'None';\n```\n\nUsed for `resizeMode` property.\n\n### InputEventArgs\n\n```typescript\ninterface InputEventArgs {\n value: string;\n keyCode: number;\n isComposed: boolean;\n}\n```\n\nEvent args for `input` event.\n\n### ChangedEventArgs\n\n```typescript\ninterface ChangedEventArgs {\n value: string;\n isInteracted: boolean;\n previousValue: string;\n}\n```\n\nEvent args for `change` event.\n\n### FocusInEventArgs\n\n```typescript\ninterface FocusInEventArgs {\n value: string;\n}\n```\n\nEvent args for `focus` event.\n\n### FocusOutEventArgs\n\n```typescript\ninterface FocusOutEventArgs {\n value: string;\n}\n```\n\nEvent args for `blur` event.\n\n---\n\n## Usage Examples\n\n### Basic Setup\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='textarea'\n placeholder='Enter text'\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n### Full-Featured Form Field\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [value, setValue] = useState('');\n\n return (\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Your feedback'\n value={value}\n input={(args) => setValue(args.value || '')}\n floatLabelType='Auto'\n maxLength={500}\n rows={6}\n cols={50}\n enabled={true}\n showClearButton={true}\n cssClass='e-outline'\n />\n );\n}\n\nexport default App;\n```\n\n### With All Event Handlers\n\n```typescript\n\u003cTextAreaComponent\n id='complete'\n placeholder='Enter text'\n created={() => console.log('Component created')}\n input={(args) => console.log('Input:', args.value)}\n change={(args) => console.log('Changed:', args.value)}\n focus={(args) => console.log('Focused')}\n blur={(args) => console.log('Blurred')}\n destroyed={() => console.log('Component destroyed')}\n/>\n```\n\n### With Adornments\n\n```typescript\n\u003cTextAreaComponent\n id='adorned'\n placeholder='Message'\n prependTemplate={() => \u003cspan>📝\u003c/span>}\n appendTemplate={() => \u003cbutton>Send\u003c/button>}\n adornmentFlow='Horizontal'\n adornmentOrientation='Horizontal'\n/>\n```\n\n### With Accessibility\n\n```typescript\n\u003cTextAreaComponent\n id='accessible'\n placeholder='Feedback'\n htmlAttributes={{\n 'aria-label': 'User feedback form',\n 'aria-describedby': 'help-text',\n 'aria-required': 'true'\n }}\n floatLabelType='Always'\n/>\n```\n\n### With Persistence\n\n```typescript\n\u003cTextAreaComponent\n id='persistent'\n placeholder='Your draft'\n enablePersistence={true}\n value={savedValue}\n/>\n```\n\n---\n\n## Import Statement\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\n```\n\n## Package\n\n- **Package:** @syncfusion/ej2-react-inputs\n- **Version:** Latest (Check npm for current version)\n- **License:** SEE LICENSE IN license\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14474,"content_sha256":"45d4f18fa6c3c1d1ee9968f6d788bef36025f543a4491989bd057e4fd39bf995"},{"filename":"references/textarea-events.md","content":"# Events in React TextArea Component\n\n## Table of Contents\n- [Created Event](#created-event)\n- [Input Event](#input-event)\n- [Change Event](#change-event)\n- [Focus Event](#focus-event)\n- [Blur Event](#blur-event)\n- [Destroyed Event](#destroyed-event)\n- [Event Patterns](#event-patterns)\n\n## Created Event\n\nThe `created` event fires when the TextArea component is created and fully initialized. Use this to perform setup actions.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const handleCreated = () => {\n console.log('TextArea component initialized');\n // Perform any setup actions\n };\n\n return (\n \u003cTextAreaComponent \n id='default'\n placeholder='Enter comments'\n created={handleCreated}\n />\n );\n}\n\nexport default App;\n```\n\n### Use Cases for Created Event\n\n- Initialize related UI components\n- Load initial data\n- Set focus programmatically\n- Trigger animations\n- Apply dynamic configuration\n\n```typescript\nconst handleCreated = () => {\n // Set initial focus\n document.getElementById('default')?.focus();\n \n // Log initialization\n console.log('Form ready for user input');\n};\n```\n\n## Input Event\n\nThe `input` event fires every time the user types or modifies the TextArea value. Use this for real-time content tracking.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n\n const handleInput = (args: InputEventArgs) => {\n const length = (args.value || '').length;\n setCharCount(length);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='editor'\n input={handleInput}\n placeholder='Start typing'\n />\n \u003cp>Characters: {charCount}\u003c/p>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### InputEventArgs Properties\n\n```typescript\ninterface InputEventArgs {\n value: string; // Current textarea value\n keyCode: number; // Keyboard key code\n isComposed: boolean; // Composition event flag\n}\n```\n\n### Real-Time Use Cases\n\n```typescript\nconst handleInput = (args: InputEventArgs) => {\n // Character count\n const count = (args.value || '').length;\n \n // Word count\n const words = (args.value || '').trim().split(/\\s+/).length;\n \n // Line count\n const lines = (args.value || '').split('\\n').length;\n \n // Search highlighting\n const searchMatches = (args.value || '').match(/pattern/g)?.length || 0;\n};\n```\n\n## Change Event\n\nThe `change` event fires when the content changes and focus is lost. Use this for form submission or validation after user editing.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { ChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const handleChange = (args: ChangedEventArgs) => {\n console.log('Value changed to:', args.value);\n // Validate or save\n };\n\n return (\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Your feedback'\n change={handleChange}\n />\n );\n}\n\nexport default App;\n```\n\n### ChangedEventArgs Properties\n\n```typescript\ninterface ChangedEventArgs {\n value: string; // New textarea value\n isInteracted: boolean; // User-initiated change\n previousValue: string; // Previous value\n}\n```\n\n### Change Event Use Cases\n\n```typescript\nconst handleChange = (args: ChangedEventArgs) => {\n // Auto-save to database\n if (args.value && args.isInteracted) {\n saveToDatabase(args.value);\n }\n \n // Validate input\n validateInput(args.value);\n \n // Update preview\n updatePreview(args.value);\n};\n```\n\n## Focus Event\n\nThe `focus` event fires when the TextArea gains focus. Use this to highlight the field or show help text.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { FocusInEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isFocused, setIsFocused] = useState(false);\n\n const handleFocus = (args: FocusInEventArgs) => {\n console.log('TextArea focused');\n setIsFocused(true);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='message'\n placeholder='Click to focus'\n focus={handleFocus}\n />\n {isFocused && \u003cp className='help-text'>Help: Enter your message here\u003c/p>}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### FocusInEventArgs Properties\n\n```typescript\ninterface FocusInEventArgs {\n value: string; // Current textarea value\n}\n```\n\n### Focus Event Use Cases\n\n```typescript\nconst handleFocus = (args: FocusInEventArgs) => {\n // Show helper text\n showHelpText();\n \n // Highlight related fields\n highlightRelatedFields();\n \n // Log user engagement\n logAnalytics('textarea_focused');\n \n // Clear previous errors\n clearErrorMessages();\n};\n```\n\n## Blur Event\n\nThe `blur` event fires when focus is lost. Use this for validation or cleanup.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { FocusOutEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [error, setError] = useState('');\n\n const handleBlur = (args: FocusOutEventArgs) => {\n console.log('TextArea lost focus');\n \n if (!args.value || args.value.trim() === '') {\n setError('Field is required');\n } else {\n setError('');\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Your feedback'\n blur={handleBlur}\n />\n {error && \u003cp className='error'>{error}\u003c/p>}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### FocusOutEventArgs Properties\n\n```typescript\ninterface FocusOutEventArgs {\n value: string; // Current textarea value\n}\n```\n\n### Blur Event Use Cases\n\n```typescript\nconst handleBlur = (args: FocusOutEventArgs) => {\n // Validate on blur\n validateAndShowError(args.value);\n \n // Trim whitespace\n trimValue(args.value);\n \n // Format content\n formatContent(args.value);\n \n // Hide helper text\n hideHelpText();\n};\n```\n\n## Destroyed Event\n\nThe `destroyed` event fires when the TextArea component is destroyed or removed from the DOM. Use this for cleanup.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const handleDestroyed = () => {\n console.log('TextArea component destroyed');\n // Cleanup: unsubscribe events, clear timers, etc.\n };\n\n return (\n \u003cTextAreaComponent \n id='temporary'\n placeholder='Temporary textarea'\n destroyed={handleDestroyed}\n />\n );\n}\n\nexport default App;\n```\n\n### Destroyed Event Use Cases\n\n```typescript\nconst handleDestroyed = () => {\n // Clear watchers\n unsubscribeDataWatcher();\n \n // Clear timers\n clearInterval(autoSaveTimer);\n \n // Remove event listeners\n removeCustomEventListeners();\n \n // Save final state\n saveFinalState();\n};\n```\n\n## Event Patterns\n\n### Real-Time Character Counter\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [stats, setStats] = useState({\n chars: 0,\n words: 0,\n lines: 1\n });\n\n const handleInput = (args: InputEventArgs) => {\n const value = args.value || '';\n setStats({\n chars: value.length,\n words: value.trim() ? value.trim().split(/\\s+/).length : 0,\n lines: value.split('\\n').length\n });\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='counter'\n input={handleInput}\n placeholder='Type here'\n rows={5}\n />\n \u003cdiv className='stats'>\n \u003cspan>Chars: {stats.chars}\u003c/span>\n \u003cspan>Words: {stats.words}\u003c/span>\n \u003cspan>Lines: {stats.lines}\u003c/span>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Form Validation Flow\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { FocusOutEventArgs, InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [feedback, setFeedback] = useState({\n value: '',\n isTouched: false,\n error: ''\n });\n\n const handleInput = (args: InputEventArgs) => {\n setFeedback(prev => ({\n ...prev,\n value: args.value || '',\n isTouched: true\n }));\n };\n\n const handleBlur = (args: FocusOutEventArgs) => {\n let error = '';\n if (!args.value || args.value.trim() === '') {\n error = 'Feedback is required';\n } else if (args.value.length \u003c 10) {\n error = 'Minimum 10 characters';\n }\n \n setFeedback(prev => ({\n ...prev,\n error\n }));\n };\n\n const handleChange = (args) => {\n if (feedback.error) {\n // Auto-validate on blur + input to clear errors\n setFeedback(prev => ({\n ...prev,\n error: ''\n }));\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='form-textarea'\n value={feedback.value}\n input={handleInput}\n blur={handleBlur}\n change={handleChange}\n placeholder='Your feedback'\n cssClass={feedback.error ? 'e-error' : ''}\n />\n {feedback.isTouched && feedback.error && (\n \u003cp className='error'>{feedback.error}\u003c/p>\n )}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Multi-Field Coordination\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [formData, setFormData] = useState({\n title: '',\n description: ''\n });\n const [isValid, setIsValid] = useState(false);\n\n const handleTitleChange = (e: React.ChangeEvent\u003cHTMLInputElement>) => {\n setFormData(prev => ({\n ...prev,\n title: e.target.value\n }));\n checkFormValidity();\n };\n\n const handleDescriptionInput = (args: InputEventArgs) => {\n setFormData(prev => ({\n ...prev,\n description: args.value || ''\n }));\n checkFormValidity();\n };\n\n const checkFormValidity = () => {\n const valid = formData.title.length > 0 && formData.description.length > 10;\n setIsValid(valid);\n };\n\n return (\n \u003cform>\n \u003cinput \n type='text'\n value={formData.title}\n onChange={handleTitleChange}\n placeholder='Title'\n />\n \u003cTextAreaComponent \n id='description'\n value={formData.description}\n input={handleDescriptionInput}\n placeholder='Description'\n />\n \u003cbutton disabled={!isValid}>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n## Event Listener Best Practices\n\n- **Input event**: Real-time operations (character count, preview, search)\n- **Change event**: Form submission, database saves, validation\n- **Focus event**: UI feedback, help text, analytics\n- **Blur event**: Validation, cleanup, state updates\n- **Created event**: Initialization, setup\n- **Destroyed event**: Cleanup, unsubscribe\n\n## Performance Tips\n\n- Use `change` instead of `input` for expensive operations (API calls)\n- Debounce `input` event handlers for auto-save\n- Unsubscribe from events in `destroyed` to prevent memory leaks\n- Use `input` for UI feedback, `change` for persistence\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11806,"content_sha256":"8100f21cfd6e44d9838d7fb81bec3f9805eb9968112dc7bd139e86c0a8d1e952"},{"filename":"references/textarea-floating-label.md","content":"# Floating Label in React TextArea Component\n\n## Table of Contents\n- [Overview](#overview)\n- [Float Label Types](#float-label-types)\n- [Auto Floating Label](#auto-floating-label)\n- [Always Floating Label](#always-floating-label)\n- [Never Floating Label](#never-floating-label)\n- [Localization](#localization)\n- [Styling Floating Labels](#styling-floating-labels)\n\n## Overview\n\nThe floating label functionality enhances user experience by displaying placeholder text that automatically floats above the TextArea when the user interacts with it. This provides a clean, modern interface that maintains context while the user types.\n\nThe `floatLabelType` property controls this behavior with three options: `Auto`, `Always`, and `Never`.\n\n## Float Label Types\n\n### Auto Floating Label\n\nThe placeholder text floats above the TextArea when it receives focus or when the user begins typing. The label returns to its initial placeholder position when focus is lost and the TextArea is empty.\n\n**Best for:** General form fields where you want minimal visual clutter until interaction begins.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n placeholder='Enter your comments'\n floatLabelType='Auto'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n**Behavior:**\n- Initial state: Placeholder visible inside the TextArea\n- On focus: Placeholder floats above the field\n- After typing: Placeholder stays floating\n- On blur with empty field: Placeholder returns to original position\n- On blur with content: Placeholder remains floating\n\n### Always Floating Label\n\nThe placeholder text always remains floating above the TextArea, regardless of focus or content state.\n\n**Best for:** Forms where you want persistent labels for accessibility and clarity.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n placeholder='Enter your comments'\n floatLabelType='Always'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n**Behavior:**\n- The label is always visible above the TextArea\n- Never returns to placeholder position\n- Provides consistent visual layout\n\n### Never Floating Label\n\nThe placeholder text never floats. It remains in its default position inside the TextArea and disappears when the user starts typing.\n\n**Best for:** Compact interfaces where visual space is limited or when using alternative labeling methods.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n placeholder='Enter your comments'\n floatLabelType='Never'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n**Behavior:**\n- Placeholder remains inside the TextArea\n- Never floats above the field\n- Disappears when user types\n\n## Combining with Other Features\n\n### Floating Label with Max Length\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Your feedback'\n floatLabelType='Auto'\n maxLength={500}\n showClearButton={true}\n />\n );\n}\n\nexport default App;\n```\n\n### Floating Label with Validation States\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isValid, setIsValid] = useState(true);\n\n const handleChange = (args) => {\n setIsValid((args.value || '').length > 0);\n };\n\n return (\n \u003cTextAreaComponent \n id='message'\n placeholder='Enter message'\n floatLabelType='Auto'\n cssClass={isValid ? 'e-success' : 'e-error'}\n change={handleChange}\n />\n );\n}\n\nexport default App;\n```\n\n### Floating Label with Custom Sizing\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='description'\n placeholder='Product description'\n floatLabelType='Always'\n rows={6}\n cols={50}\n cssClass='e-outline'\n />\n );\n}\n\nexport default App;\n```\n\n## Localization\n\n### Placeholder with Localization\n\nUse the `locale` property to localize placeholder text to different cultures:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='comments'\n placeholder='Veuillez entrer vos commentaires'\n locale='fr-BE'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Load Translation for German Culture\n\nUse the `L10n` class to load translation objects for specific cultures:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { L10n } from '@syncfusion/ej2-base';\nimport * as React from 'react';\nimport './App.css';\n\n// Load German locale strings\nL10n.load({\n 'de-DE': {\n 'textarea': { 'placeholder': 'Geben Sie Ihre Kommentare ein' }\n }\n});\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='comments'\n locale='de-DE'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Load French Locale\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { L10n } from '@syncfusion/ej2-base';\nimport * as React from 'react';\nimport './App.css';\n\nL10n.load({\n 'fr-FR': {\n 'textarea': { 'placeholder': 'Entrez vos commentaires' }\n }\n});\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='feedback'\n locale='fr-FR'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Multiple Locales\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { L10n } from '@syncfusion/ej2-base';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nL10n.load({\n 'de-DE': {\n 'textarea': { 'placeholder': 'Geben Sie Ihre Kommentare ein' }\n },\n 'fr-FR': {\n 'textarea': { 'placeholder': 'Entrez vos commentaires' }\n },\n 'es-ES': {\n 'textarea': { 'placeholder': 'Ingrese sus comentarios' }\n }\n});\n\nfunction App() {\n const [locale, setLocale] = useState('en-US');\n\n return (\n \u003cdiv>\n \u003cdiv>\n \u003cbutton onClick={() => setLocale('en-US')}>English\u003c/button>\n \u003cbutton onClick={() => setLocale('de-DE')}>German\u003c/button>\n \u003cbutton onClick={() => setLocale('fr-FR')}>French\u003c/button>\n \u003cbutton onClick={() => setLocale('es-ES')}>Spanish\u003c/button>\n \u003c/div>\n \u003cTextAreaComponent \n id='message'\n locale={locale}\n floatLabelType='Auto'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Styling Floating Labels\n\n### Change Floating Label Color\n\nYou can customize the floating label color for different validation states:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='success'\n placeholder='Success state'\n floatLabelType='Auto'\n cssClass='e-success'\n />\n \u003cTextAreaComponent \n id='warning'\n placeholder='Warning state'\n floatLabelType='Auto'\n cssClass='e-warning'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\nAdd this CSS to your stylesheet:\n\n```css\n/* For Success state */\n.e-float-input.e-success label.e-float-text,\n.e-float-input.e-success input:focus ~ label.e-float-text,\n.e-float-input.e-success textarea:focus ~ label.e-float-text {\n color: #22b24b;\n}\n\n/* For Warning state */\n.e-float-input.e-warning label.e-float-text,\n.e-float-input.e-warning input:focus ~ label.e-float-text,\n.e-float-input.e-warning textarea:focus ~ label.e-float-text {\n color: #ffca1c;\n}\n```\n\n## Best Practices\n\n- **Auto** for standard forms - provides modern UX with minimal clutter\n- **Always** for accessibility-critical applications - ensures labels are always visible\n- **Never** when using separate label elements - avoids duplicate labeling\n- Always provide meaningful placeholder text\n- Use localization for multi-language support\n- Combine with `cssClass` for proper styling\n- Test with keyboard navigation for accessibility\n\n## Common Issues\n\n**Label not floating:**\n- Ensure `floatLabelType` is set correctly (not default 'Never')\n- Check that placeholder text is provided\n- Verify CSS is properly imported\n\n**Label stuck in floating position:**\n- This is expected behavior - ensure appropriate `floatLabelType`\n- For 'Auto', label returns only when field is empty and unfocused\n\n**Localization not working:**\n- Verify `L10n.load()` is called before component renders\n- Check locale code matches exactly (case-sensitive)\n- Ensure 'textarea' key is present in locale object\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9303,"content_sha256":"c1ff3e72a4359277dfc009edeab5fbd5e054e38bb644b860a2295b2cb476cda0"},{"filename":"references/textarea-form-support.md","content":"# Form Support in React TextArea Component\n\n## Table of Contents\n- [Overview](#overview)\n- [HTML Form Integration](#html-form-integration)\n- [FormValidator Integration](#formvalidator-integration)\n- [Validation Rules](#validation-rules)\n- [Form Submission](#form-submission)\n- [Error Display](#error-display)\n\n## Overview\n\nThe TextArea component seamlessly integrates with HTML forms and Syncfusion's FormValidator component. This enables efficient submission of multiline text data, comprehensive validation, and error messaging.\n\n## HTML Form Integration\n\n### Basic Form with TextArea\n\nIntegrate TextArea directly in an HTML form:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget as HTMLFormElement);\n console.log('Form data:', Object.fromEntries(formData));\n };\n\n return (\n \u003cform onSubmit={handleSubmit}>\n \u003cTextAreaComponent \n id='comments'\n name='myTextarea'\n placeholder='Enter your comments'\n floatLabelType='Auto'\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Required Field Validation\n\nMark textarea as required:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cform>\n \u003cTextAreaComponent \n id='feedback'\n name='feedback'\n placeholder='Your feedback'\n floatLabelType='Auto'\n required={true}\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Form with Multiple Fields\n\nCombine TextArea with other form inputs:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [formData, setFormData] = React.useState({\n name: '',\n email: '',\n comments: ''\n });\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n console.log('Submitted:', formData);\n // Send to API\n };\n\n return (\n \u003cform onSubmit={handleSubmit}>\n \u003cdiv>\n \u003cinput \n type='text'\n name='name'\n placeholder='Full Name'\n value={formData.name}\n onChange={(e) => setFormData({...formData, name: e.target.value})}\n />\n \u003c/div>\n \u003cdiv>\n \u003cinput \n type='email'\n name='email'\n placeholder='Email'\n value={formData.email}\n onChange={(e) => setFormData({...formData, email: e.target.value})}\n />\n \u003c/div>\n \u003cdiv>\n \u003cTextAreaComponent \n id='comments'\n name='comments'\n placeholder='Comments'\n value={formData.comments}\n input={(args) => setFormData({...formData, comments: args.value || ''})}\n floatLabelType='Auto'\n />\n \u003c/div>\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n## FormValidator Integration\n\nThe TextArea component integrates seamlessly with Syncfusion's `FormValidator` component for comprehensive form validation.\n\n### Basic FormValidator Setup\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nlet formValidator;\n\nfunction App() {\n useEffect(() => {\n const options = {\n rules: {\n comments: {\n required: [true, '* Please enter your comments']\n }\n }\n };\n \n formValidator = new FormValidator('#form1', options);\n }, []);\n\n return (\n \u003cform id='form1'>\n \u003cTextAreaComponent \n id='comments'\n name='comments'\n placeholder='Enter your comments'\n floatLabelType='Auto'\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Validation with Multiple Rules\n\nApply multiple validation rules to a single TextArea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nlet formValidator;\n\nfunction App() {\n useEffect(() => {\n const options = {\n rules: {\n message: {\n required: [true, '* Message is required'],\n minLength: [10, '* Minimum 10 characters required'],\n maxLength: [500, '* Maximum 500 characters allowed']\n }\n }\n };\n \n formValidator = new FormValidator('#form1', options);\n }, []);\n\n return (\n \u003cform id='form1'>\n \u003cTextAreaComponent \n id='message'\n name='message'\n placeholder='Enter your message (10-500 chars)'\n floatLabelType='Auto'\n maxLength={500}\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n## Validation Rules\n\n### Required Field\n\n```typescript\nrules: {\n feedback: {\n required: [true, '* Feedback is required']\n }\n}\n```\n\n### Minimum Length\n\nEnforce minimum character count:\n\n```typescript\nrules: {\n description: {\n minLength: [20, '* Minimum 20 characters required']\n }\n}\n```\n\n### Maximum Length\n\nSet maximum character limit:\n\n```typescript\nrules: {\n bio: {\n maxLength: [200, '* Maximum 200 characters allowed']\n }\n}\n```\n\n### Pattern Matching\n\nValidate against a regex pattern:\n\n```typescript\nrules: {\n code: {\n required: [true, '* Code is required'],\n pattern: [/^[A-Z0-9]{5,10}$/, '* Invalid code format']\n }\n}\n```\n\n### Custom Validation\n\nDefine custom validation logic:\n\n```typescript\nrules: {\n email: {\n required: [true, '* Email is required'],\n email: [true, '* Please enter a valid email']\n },\n message: {\n required: [true, '* Message is required'],\n min: [5, '* Message must be at least 5 characters']\n }\n}\n```\n\n## Form Submission\n\n### Complete Feedback Form Example\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nlet formValidator;\n\nfunction App() {\n const [submitStatus, setSubmitStatus] = useState('');\n\n useEffect(() => {\n const options = {\n rules: {\n email: {\n required: [true, '* Please enter valid email'],\n email: [true, '* Please enter a valid email address']\n },\n comments: {\n required: [true, '* Please enter your comments'],\n minLength: [10, '* Minimum 10 characters required']\n }\n }\n };\n \n formValidator = new FormValidator('#form1', options);\n }, []);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n \n if (formValidator.validate()) {\n const formElement = e.currentTarget as HTMLFormElement;\n const formData = new FormData(formElement);\n \n console.log('Form submitted with:', Object.fromEntries(formData));\n setSubmitStatus('Form submitted successfully!');\n \n // Reset form\n formElement.reset();\n setTimeout(() => setSubmitStatus(''), 3000);\n }\n };\n\n return (\n \u003cdiv>\n \u003cform id='form1' onSubmit={handleSubmit}>\n \u003cdiv className='form-group'>\n \u003cdiv className='e-float-input'>\n \u003clabel>Email\u003c/label>\n \u003cinput \n type='email' \n id='email' \n name='email'\n data-required-message='Required field'\n required\n />\n \u003cspan className='e-float-line'>\u003c/span>\n \u003c/div>\n \u003cdiv id='emailError'>\u003c/div>\n \u003c/div>\n\n \u003cdiv className='form-group'>\n \u003clabel>Comments\u003c/label>\n \u003cTextAreaComponent \n id='comments'\n name='comments'\n placeholder='Enter your comments'\n floatLabelType='Auto'\n required={true}\n />\n \u003cdiv id='commentError'>\u003c/div>\n \u003c/div>\n\n \u003cdiv className='form-actions'>\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003cbutton type='reset'>Reset\u003c/button>\n \u003c/div>\n \u003c/form>\n \n {submitStatus && \u003cp className='success'>{submitStatus}\u003c/p>}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Error Display\n\n### Error Container Pattern\n\nDisplay validation errors in designated containers:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nlet formValidator;\n\nfunction App() {\n useEffect(() => {\n const options = {\n rules: {\n message: {\n required: [true, '* Message is required'],\n minLength: [5, '* Minimum 5 characters']\n }\n }\n };\n \n formValidator = new FormValidator('#myForm', options);\n }, []);\n\n return (\n \u003cform id='myForm'>\n \u003cdiv className='form-group'>\n \u003clabel>Your Message:\u003c/label>\n \u003cTextAreaComponent \n id='message'\n name='message'\n placeholder='Enter message'\n data-msg-containerid='messageError'\n />\n \u003cdiv id='messageError' className='error-container'>\u003c/div>\n \u003c/div>\n \n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Custom Error Styling\n\n```css\n.error-container {\n color: #d32f2f;\n font-size: 0.875rem;\n margin-top: 4px;\n display: none;\n}\n\n.error-container.show {\n display: block;\n}\n\n.e-field.e-error {\n border-color: #d32f2f;\n background-color: #ffebee;\n}\n```\n\n### Real-Time Error Feedback\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [text, setText] = useState('');\n const [errors, setErrors] = useState\u003cstring[]>([]);\n\n const validateText = (value: string) => {\n const newErrors: string[] = [];\n \n if (!value || value.trim() === '') {\n newErrors.push('Text is required');\n } else if (value.length \u003c 5) {\n newErrors.push('Minimum 5 characters required');\n } else if (value.length > 200) {\n newErrors.push('Maximum 200 characters exceeded');\n }\n \n setErrors(newErrors);\n };\n\n const handleInput = (args) => {\n const value = args.value || '';\n setText(value);\n validateText(value);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='feedback'\n value={text}\n input={handleInput}\n placeholder='Enter feedback'\n floatLabelType='Auto'\n cssClass={errors.length > 0 ? 'e-error' : ''}\n />\n {errors.length > 0 && (\n \u003cdiv className='error-messages'>\n {errors.map((error, i) => (\n \u003cp key={i} className='error-text'>{error}\u003c/p>\n ))}\n \u003c/div>\n )}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Best Practices\n\n- Always use `name` attribute for form data collection\n- Provide clear validation messages\n- Set `required={true}` for mandatory fields\n- Use `maxLength` property with validation rules for consistency\n- Display errors near the input field\n- Test form submission with various inputs\n- Use `floatLabelType='Auto'` for modern UX\n- Validate on both client and server side\n- Clear errors when user corrects the input\n- Provide visual feedback for validation states\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11662,"content_sha256":"1e3eee2e1a252572c4b5b7219544f118b7fa2044e6cd2f5c3e3240c1d1bab9ec"},{"filename":"references/textarea-getting-started.md","content":"# Getting Started with React TextArea Component\n\n## Table of Contents\n- [Installation](#installation)\n- [Setup](#setup)\n- [Basic Implementation](#basic-implementation)\n- [CSS Configuration](#css-configuration)\n- [Getting and Setting Values](#getting-and-setting-values)\n- [First Render](#first-render)\n\n## Installation\n\n### Install the TextArea Package\n\nThe Syncfusion TextArea component is part of the `@syncfusion/ej2-react-inputs` package published on npmjs.com.\n\n```bash\nnpm install @syncfusion/ej2-react-inputs --save\n```\n\nThe `--save` flag adds the package to your `package.json` dependencies section.\n\n## Setup\n\n### Vite Project Setup (Recommended)\n\nVite provides faster development and optimized builds compared to traditional tools. To create a new React application with Vite:\n\n```bash\nnpm create vite@latest my-app -- --template react-ts\ncd my-app\nnpm run dev\n```\n\nFor JavaScript environment (without TypeScript):\n\n```bash\nnpm create vite@latest my-app -- --template react\ncd my-app\nnpm run dev\n```\n\nFor detailed steps, refer to the [Vite installation guide](https://vitejs.dev/guide).\n\n### Create React App (Alternative)\n\nFor traditional React setup:\n\n```bash\nnpx create-react-app my-app\ncd my-app\nnpm start\n```\n\n## CSS Configuration\n\n### Add Syncfusion Styles\n\nThe TextArea component requires CSS files from the Syncfusion package. Add these imports to your **src/App.css** file:\n\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/textarea/index.css\";\n```\n\nThen import `App.css` in your **src/App.tsx** (or App.jsx) file:\n\n```typescript\nimport './App.css';\n```\n\n## Basic Implementation\n\n### Simple TextArea\n\nAdd the TextArea component to **src/App.tsx**:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent id='default' />\n );\n}\n\nexport default App;\n```\n\n### TextArea with Placeholder\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n placeholder='Enter your comments' \n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### TextArea with Floating Label\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n placeholder='Enter your comments'\n floatLabelType='Auto'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## First Render\n\n### Running the Application\n\nExecute the development server:\n\n```bash\nnpm run dev\n```\n\nThe application will:\n1. Compile your code\n2. Start a local development server\n3. Open in your default browser\n\nThe TextArea component will render as an empty multiline text input field.\n\n### Output Structure\n\n```html\n\u003cdiv class='wrap'>\n \u003ctextarea \n id='default' \n class='e-field e-input'\n placeholder='Enter your comments'\n >\u003c/textarea>\n\u003c/div>\n```\n\n## Getting and Setting Values\n\n### Set Initial Value with Property\n\nUse the `value` property to set the initial content:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n value='This is initial content'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Set Value with State Variable\n\nManage the textarea value with React state for dynamic updates:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [textValue, setTextValue] = useState('Default comment text');\n\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n value={textValue}\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Get Value Programmatically\n\nRetrieve the textarea value when needed (e.g., on button click):\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [textValue, setTextValue] = useState('Default comment');\n\n const onButtonClick = () => {\n console.log('TextArea value:', textValue);\n // Use the value for form submission, API call, etc.\n };\n\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default' \n value={textValue}\n />\n \u003cbutton onClick={onButtonClick}>Get Value\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Detect Value Changes\n\nUse the `input` event for real-time value change detection or the `change` event for when focus is lost:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const handleInput = (args: InputEventArgs) => {\n console.log('Current value (real-time):', args.value);\n };\n\n const handleChange = (args) => {\n console.log('Value changed (on blur):', args.value);\n };\n\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default'\n input={handleInput}\n change={handleChange}\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### State Update on Change\n\nAutomatically update state when the textarea value changes:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { ChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [textValue, setTextValue] = useState('');\n\n const handleChange = (args: ChangedEventArgs) => {\n setTextValue(args.value || '');\n };\n\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent \n id='default'\n value={textValue}\n change={handleChange}\n />\n \u003cp>Current length: {textValue.length}\u003c/p>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Next Steps\n\n- Configure floating labels for better UX\n- Add form validation with FormValidator\n- Set maximum character limits\n- Customize styling and appearance\n- Implement resize behavior\n- Add adornments for additional functionality\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6557,"content_sha256":"4a153519fe83f8b9a3b37cf843fe7bf30d5f71e18b1856c66838cf19938d62f4"},{"filename":"references/textarea-max-length.md","content":"# Maximum Length in React TextArea Component\n\nEnforce character limit restrictions to control input length and prevent users from exceeding specified bounds. The `maxLength` property defines the maximum number of characters allowed.\n\n## Setting Maximum Length\n\n### Basic Usage\n\nUse the `maxLength` property to restrict character input:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='comments'\n placeholder='Enter your comments'\n maxLength={500}\n />\n );\n}\n\nexport default App;\n```\n\nWhen the user reaches the character limit, the TextArea prevents further input, ensuring compliance with the defined character limit.\n\n## Character Limit Enforcement\n\n### Automatic Prevention\n\nOnce the character limit is reached, users cannot type additional characters:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='bio'\n placeholder='Your bio (max 200 chars)'\n maxLength={200}\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n**Behavior:**\n- Characters can be entered up to the limit\n- Input is rejected when limit is reached\n- User can still delete or edit existing content\n- Paste operations are truncated to fit the limit\n\n## User Feedback\n\n### Display Character Count\n\nShow users how many characters they've entered and how many remain:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n const maxChars = 500;\n const remaining = maxChars - charCount;\n\n const handleInput = (args) => {\n setCharCount((args.value || '').length);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='message'\n placeholder='Enter your message'\n maxLength={maxChars}\n input={handleInput}\n floatLabelType='Auto'\n />\n \u003cp className='char-info'>\n {charCount} / {maxChars} characters\n \u003c/p>\n {remaining \u003c= 50 && (\n \u003cp className='warning'>\n {remaining} characters remaining\n \u003c/p>\n )}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Character Count with Progress Bar\n\nVisual representation of character usage:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n const maxChars = 500;\n const percentage = (charCount / maxChars) * 100;\n\n const handleInput = (args) => {\n setCharCount((args.value || '').length);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Share your feedback'\n maxLength={maxChars}\n input={handleInput}\n />\n \n \u003cdiv className='progress-container'>\n \u003cdiv \n className='progress-bar'\n style={{width: `${percentage}%`}}\n >\u003c/div>\n \u003c/div>\n \n \u003cspan className='char-count'>\n {charCount} of {maxChars}\n \u003c/span>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Styling Based on Character Count\n\nApply different styles as users approach the limit:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n const maxChars = 500;\n const percentage = (charCount / maxChars) * 100;\n\n const getStatusClass = () => {\n if (percentage \u003c 50) return 'status-good';\n if (percentage \u003c 80) return 'status-warning';\n return 'status-danger';\n };\n\n const handleInput = (args) => {\n setCharCount((args.value || '').length);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='essay'\n placeholder='Write your essay'\n maxLength={maxChars}\n input={handleInput}\n cssClass={getStatusClass()}\n />\n \n \u003cdiv className={`char-status ${getStatusClass()}`}>\n \u003cspan>{charCount}/{maxChars}\u003c/span>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Form Validation\n\n### Combining with Validation Rules\n\nUse maxLength with FormValidator:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nlet formValidator;\n\nfunction App() {\n useEffect(() => {\n const options = {\n rules: {\n description: {\n required: [true, '* Description is required'],\n minLength: [50, '* Minimum 50 characters'],\n maxLength: [500, '* Maximum 500 characters']\n }\n }\n };\n \n formValidator = new FormValidator('#form1', options);\n }, []);\n\n return (\n \u003cform id='form1'>\n \u003cTextAreaComponent \n id='description'\n name='description'\n placeholder='Product description (50-500 chars)'\n maxLength={500}\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n## Best Practices\n\n### Setting Appropriate Limits\n\nChoose limits based on use case:\n\n```typescript\n// Short feedback (Twitter-like)\n\u003cTextAreaComponent maxLength={280} />\n\n// Medium form textarea\n\u003cTextAreaComponent maxLength={500} />\n\n// Long essay or comment\n\u003cTextAreaComponent maxLength={2000} />\n\n// Generous limit for detailed content\n\u003cTextAreaComponent maxLength={5000} />\n```\n\n### Mobile-Friendly Implementation\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n const maxChars = 300; // Lower for mobile\n\n const handleInput = (args) => {\n setCharCount((args.value || '').length);\n };\n\n return (\n \u003cdiv className='mobile-textarea'>\n \u003cTextAreaComponent \n id='feedback'\n maxLength={maxChars}\n input={handleInput}\n placeholder='Your feedback'\n showClearButton={true}\n />\n \n \u003cdiv className='mobile-info'>\n \u003cspan className='count'>{charCount}/{maxChars}\u003c/span>\n \u003cp className='hint'>\n {maxChars - charCount} characters left\n \u003c/p>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Edge Cases\n\n### Paste Behavior\n\nPasted content is truncated to fit within the limit:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n // When user pastes 1000 characters into maxLength={500},\n // only the first 500 characters are retained\n \n return (\n \u003cTextAreaComponent \n id='content'\n maxLength={500}\n placeholder='Paste text here (max 500 chars)'\n />\n );\n}\n\nexport default App;\n```\n\n### Initial Value Handling\n\nInitial values longer than maxLength are not truncated:\n\n```typescript\n// This will display all content even if value exceeds maxLength\n\u003cTextAreaComponent \n id='text'\n value='This is a very long text that exceeds 500 chars'\n maxLength={500}\n/>\n```\n\nTo handle this, truncate initial values:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const initialValue = 'Long text...';\n const maxChars = 500;\n \n const truncatedValue = initialValue.length > maxChars \n ? initialValue.substring(0, maxChars)\n : initialValue;\n\n return (\n \u003cTextAreaComponent \n id='text'\n value={truncatedValue}\n maxLength={maxChars}\n />\n );\n}\n\nexport default App;\n```\n\n## Real-World Examples\n\n### Comment Form with Limit\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [comment, setComment] = useState('');\n const maxChars = 500;\n const isNearLimit = comment.length > maxChars - 50;\n\n const handleSubmit = () => {\n if (comment.trim().length > 0) {\n console.log('Submitting comment:', comment);\n setComment('');\n }\n };\n\n return (\n \u003cdiv className='comment-form'>\n \u003cTextAreaComponent \n id='comment'\n value={comment}\n input={(args) => setComment(args.value || '')}\n maxLength={maxChars}\n placeholder='Share your thoughts...'\n floatLabelType='Auto'\n />\n \n \u003cdiv className='form-footer'>\n \u003cspan className={isNearLimit ? 'warning' : ''}>\n {comment.length} / {maxChars}\n \u003c/span>\n \u003cbutton \n onClick={handleSubmit}\n disabled={comment.trim().length === 0}\n >\n Post Comment\n \u003c/button>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Product Review Form\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [review, setReview] = useState('');\n const maxChars = 1000;\n const minChars = 50;\n const isValid = review.length >= minChars && review.length \u003c= maxChars;\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='review'\n value={review}\n input={(args) => setReview(args.value || '')}\n maxLength={maxChars}\n placeholder='Write your review here...'\n rows={6}\n />\n \n \u003cdiv className={`review-stats ${isValid ? 'valid' : 'invalid'}`}>\n \u003cp>{review.length} / {maxChars} characters\u003c/p>\n {review.length \u003c minChars && (\n \u003cp>Minimum {minChars} characters required\u003c/p>\n )}\n \u003c/div>\n \n \u003cbutton disabled={!isValid}>Submit Review\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10095,"content_sha256":"0794bfe3a8d637ff68023373ccea08bae5ca9f33d32c8d423420755eb7753d29"},{"filename":"references/textarea-methods.md","content":"# Methods in React TextArea Component\n\nThis section outlines the methods available for programmatic interaction with the TextArea component.\n\n## FocusIn Method\n\nThe `focusIn()` method sets focus to the textarea element, enabling keyboard interaction. Useful for directing user attention or automated workflows.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleFocusClick = () => {\n if (textareaRef.current) {\n textareaRef.current.focusIn();\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n placeholder='Click button to focus'\n />\n \u003cbutton onClick={handleFocusClick}>Focus TextArea\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Use Cases for FocusIn\n\n```typescript\nconst handleFocusClick = () => {\n // Direct user attention to textarea\n textareaRef.current?.focusIn();\n \n // Programmatically set focus after validation\n if (validationPassed) {\n textareaRef.current?.focusIn();\n }\n \n // Move focus in wizard workflow\n textareaRef.current?.focusIn();\n};\n```\n\n## FocusOut Method\n\nThe `focusOut()` method removes focus from the textarea element, ending keyboard interaction.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleBlurClick = () => {\n if (textareaRef.current) {\n textareaRef.current.focusOut();\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n placeholder='Click button to remove focus'\n />\n \u003cbutton onClick={handleBlurClick}>Blur TextArea\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Use Cases for FocusOut\n\n```typescript\nconst handleBlurClick = () => {\n // Move focus to next field\n textareaRef.current?.focusOut();\n nextFieldRef.current?.focusIn();\n \n // Close modal/dialog\n textareaRef.current?.focusOut();\n closeModal();\n};\n```\n\n## GetPersistData Method\n\nThe `getPersistData()` method retrieves properties needed for persistence state. It returns an object containing configuration options and state information for maintaining data across sessions.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleGetPersistData = () => {\n if (textareaRef.current) {\n const persistData = textareaRef.current.getPersistData();\n console.log('Persist Data:', persistData);\n // Save to localStorage or session storage\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n value='Sample content'\n enablePersistence={true}\n />\n \u003cbutton onClick={handleGetPersistData}>Get Persist Data\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Save State to LocalStorage\n\n```typescript\nconst saveState = () => {\n if (textareaRef.current) {\n const persistData = textareaRef.current.getPersistData();\n localStorage.setItem('textareaState', JSON.stringify(persistData));\n }\n};\n\nconst restoreState = () => {\n const savedState = localStorage.getItem('textareaState');\n if (savedState && textareaRef.current) {\n textareaRef.current.setPersistData(JSON.parse(savedState));\n }\n};\n```\n\n## AddAttributes Method\n\nThe `addAttributes()` method adds multiple HTML attributes to the TextArea element dynamically.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleAddAttributes = () => {\n if (textareaRef.current) {\n textareaRef.current.addAttributes({\n 'data-testid': 'textarea-field',\n 'aria-label': 'User feedback',\n 'title': 'Enter your feedback here'\n });\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n placeholder='Enter content'\n />\n \u003cbutton onClick={handleAddAttributes}>Add Attributes\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Common Attribute Additions\n\n```typescript\n// Add accessibility attributes\ntextareaRef.current?.addAttributes({\n 'aria-required': 'true',\n 'aria-describedby': 'help-text-id',\n 'aria-invalid': 'false'\n});\n\n// Add data attributes\ntextareaRef.current?.addAttributes({\n 'data-field-name': 'comments',\n 'data-required': 'true',\n 'data-max-length': '500'\n});\n\n// Add validation attributes\ntextareaRef.current?.addAttributes({\n 'data-validation': 'required|minLength:10',\n 'data-error-message': 'Invalid input'\n});\n```\n\n## RemoveAttributes Method\n\nThe `removeAttributes()` method removes multiple HTML attributes from the TextArea element.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleAddAttributes = () => {\n if (textareaRef.current) {\n textareaRef.current.addAttributes({\n 'title': 'User Feedback',\n 'data-info': 'This is feedback form'\n });\n }\n };\n\n const handleRemoveAttributes = () => {\n if (textareaRef.current) {\n textareaRef.current.removeAttributes(['title', 'data-info']);\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n placeholder='Enter content'\n />\n \u003cbutton onClick={handleAddAttributes}>Add Attributes\u003c/button>\n \u003cbutton onClick={handleRemoveAttributes}>Remove Attributes\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Attribute Cleanup\n\n```typescript\nconst cleanupAttributes = () => {\n textareaRef.current?.removeAttributes([\n 'data-testid',\n 'data-validation',\n 'aria-invalid',\n 'title'\n ]);\n};\n```\n\n## Destroy Method\n\nThe `destroy()` method removes the component from the DOM and detaches all event handlers. It also maintains the original textarea element.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n const handleDestroy = () => {\n if (textareaRef.current) {\n textareaRef.current.destroy();\n console.log('TextArea component destroyed');\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='textarea'\n placeholder='This will be destroyed'\n />\n \u003cbutton onClick={handleDestroy}>Destroy Component\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Cleanup in Unmount\n\n```typescript\nimport { useEffect } from 'react';\n\nuseEffect(() => {\n return () => {\n // Cleanup when component unmounts\n textareaRef.current?.destroy();\n };\n}, []);\n```\n\n## Practical Examples\n\n### Multi-Step Form with Focus Management\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n const [step, setStep] = useState(1);\n\n const handleNext = () => {\n if (step === 1) {\n // Validate and move focus\n textareaRef.current?.focusOut();\n setStep(2);\n }\n };\n\n const handlePrevious = () => {\n if (step === 2) {\n setStep(1);\n textareaRef.current?.focusIn();\n }\n };\n\n return (\n \u003cdiv>\n {step === 1 && (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='description'\n placeholder='Enter description'\n />\n \u003cbutton onClick={handleNext}>Next\u003c/button>\n \u003c/div>\n )}\n \n {step === 2 && (\n \u003cdiv>\n \u003cp>Review your input...\u003c/p>\n \u003cbutton onClick={handlePrevious}>Back\u003c/button>\n \u003c/div>\n )}\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Accessibility Enhancement\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n useEffect(() => {\n // Add accessibility attributes on mount\n if (textareaRef.current) {\n textareaRef.current.addAttributes({\n 'aria-label': 'Feedback form textarea',\n 'aria-describedby': 'feedback-help',\n 'aria-required': 'true',\n 'role': 'textbox'\n });\n }\n }, []);\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='feedback'\n placeholder='Enter feedback'\n />\n \u003cp id='feedback-help'>Please provide constructive feedback\u003c/p>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### State Persistence\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const textareaRef = useRef\u003cTextAreaComponent>(null);\n\n useEffect(() => {\n // Enable persistence\n if (textareaRef.current) {\n textareaRef.current.enablePersistence = true;\n }\n\n // Optional: Add custom persistence\n window.addEventListener('beforeunload', () => {\n if (textareaRef.current) {\n const persistData = textareaRef.current.getPersistData();\n sessionStorage.setItem('textareaBackup', persistData);\n }\n });\n\n return () => {\n textareaRef.current?.destroy();\n };\n }, []);\n\n return (\n \u003cTextAreaComponent \n ref={textareaRef}\n id='draft'\n placeholder='Your work will be saved'\n />\n );\n}\n\nexport default App;\n```\n\n## Best Practices\n\n- Use `focusIn()` to guide user attention in complex forms\n- Call `focusOut()` before programmatic field changes\n- Use `getPersistData()` for cross-session state management\n- Add accessibility attributes with `addAttributes()`\n- Remove temporary attributes with `removeAttributes()`\n- Always call `destroy()` in unmount handlers to prevent memory leaks\n- Test all methods in different browser environments\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10666,"content_sha256":"4989af5432d730e70c59eb87f29c14b6e36c2c38e8c0f2cd370708e6abfe7d61"},{"filename":"references/textarea-resize.md","content":"# Resize Behavior in React TextArea Component\n\nConfigure how users can resize the TextArea to accommodate varying content and interface preferences. The `resizeMode` property offers flexible control over resizing behavior.\n\n## Resize Modes\n\nThe `resizeMode` property accepts four values:\n\n| Mode | Description | Default? |\n|------|-------------|----------|\n| **Both** | Users can resize both height and width | ✓ Yes |\n| **Vertical** | Only vertical (height) resizing allowed | |\n| **Horizontal** | Only horizontal (width) resizing allowed | |\n| **None** | Resizing disabled | |\n\n## Both Mode (Default)\n\nUsers can resize the TextArea both vertically (height) and horizontally (width).\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='default'\n placeholder='Drag the corner to resize'\n resizeMode='Both'\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n**User Experience:**\n- Resize handle appears in the bottom-right corner\n- Dragging adjusts both dimensions\n- Default browser textarea behavior\n\n**Note:** Width adjustment works when CSS allows it. By default, the width won't auto-adjust without explicit CSS configuration.\n\n## Vertical Mode\n\nAllow only vertical (height) resizing. Users can increase or decrease the number of visible lines.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='vertical-only'\n placeholder='Resize vertically only'\n resizeMode='Vertical'\n rows={4}\n cols={50}\n />\n );\n}\n\nexport default App;\n```\n\n**Best for:**\n- Form fields where width should remain consistent\n- Responsive layouts with fixed container widths\n- Better control of layout integrity\n\n**User Experience:**\n- Resize handle only on vertical axis\n- Height can be increased/decreased\n- Width remains fixed\n\n## Horizontal Mode\n\nAllow only horizontal (width) resizing. Users can adjust the visible width.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='horizontal-only'\n placeholder='Resize horizontally only'\n resizeMode='Horizontal'\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n**Best for:**\n- Scenarios requiring fixed height but variable width\n- Code editors or specialized inputs\n- Accommodating longer lines without vertical expansion\n\n## None Mode\n\nDisable resizing entirely. The TextArea maintains fixed dimensions.\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='no-resize'\n placeholder='Cannot be resized'\n resizeMode='None'\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n**Best for:**\n- Consistent form layouts where user resizing would break design\n- Fixed-size input fields in compact interfaces\n- Design-critical layouts where dimension consistency is essential\n\n**User Experience:**\n- No resize handle visible\n- TextArea maintains specified dimensions\n- Content scrolls if it exceeds visible area\n\n## Combining with Width Property\n\nControl both dimensions with width and resizeMode:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='controlled'\n placeholder='Controlled dimensions'\n resizeMode='Vertical'\n width='100%'\n rows={5}\n />\n );\n}\n\nexport default App;\n```\n\nThis creates a full-width textarea that can only be resized vertically.\n\n## Responsive Resize Control\n\nAdjust resize behavior based on screen size:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [resizeMode, setResizeMode] = useState('Both');\n\n useEffect(() => {\n const handleResize = () => {\n if (window.innerWidth \u003c 768) {\n setResizeMode('Vertical'); // Mobile: vertical only\n } else {\n setResizeMode('Both'); // Desktop: both directions\n }\n };\n\n window.addEventListener('resize', handleResize);\n handleResize();\n\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n return (\n \u003cTextAreaComponent \n id='responsive-resize'\n placeholder='Responsive resize control'\n resizeMode={resizeMode}\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n## Fixed Height with Scrollable Content\n\nUse `None` mode for fixed dimensions with scroll for overflow:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='fixed-scroll'\n placeholder='Fixed size with scrollbars'\n resizeMode='None'\n rows={5}\n cols={40}\n width='400px'\n />\n );\n}\n\nexport default App;\n```\n\nCSS for scrollable behavior:\n\n```css\n#fixed-scroll {\n overflow: auto;\n}\n```\n\n## User-Controlled Sizing with Constraints\n\nAllow resizing within limits:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='limited-resize'\n placeholder='Resizable with constraints'\n resizeMode='Vertical'\n rows={4}\n cols={50}\n width='500px'\n />\n );\n}\n\nexport default App;\n```\n\nWith CSS constraints:\n\n```css\n#limited-resize {\n min-height: 120px; /* At least 4 rows */\n max-height: 400px; /* Maximum 20+ rows */\n min-width: 300px;\n max-width: 800px;\n}\n```\n\n## Combining with Other Features\n\n### Resize with Max Length\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [charCount, setCharCount] = useState(0);\n\n return (\n \u003cTextAreaComponent \n id='limited-content'\n placeholder='Resizable with character limit'\n resizeMode='Vertical'\n maxLength={500}\n input={(args) => setCharCount((args.value || '').length)}\n rows={5}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n### Resize with Floating Labels\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='float-resize'\n placeholder='Enter your message'\n floatLabelType='Auto'\n resizeMode='Vertical'\n rows={4}\n cols={45}\n />\n );\n}\n\nexport default App;\n```\n\n### Resize with Adornments\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const appendContent = () => (\n \u003cbutton className='send-btn'>Send\u003c/button>\n );\n\n return (\n \u003cTextAreaComponent \n id='adorned-resize'\n placeholder='Message with action'\n resizeMode='Vertical'\n appendTemplate={appendContent}\n rows={4}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n## Layout Considerations\n\n### Fixed Layout with No Resize\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cform className='form-layout'>\n \u003cdiv className='form-row'>\n \u003clabel>Name\u003c/label>\n \u003cinput type='text' />\n \u003c/div>\n\n \u003cdiv className='form-row'>\n \u003clabel>Email\u003c/label>\n \u003cinput type='email' />\n \u003c/div>\n\n \u003cdiv className='form-row'>\n \u003clabel>Message\u003c/label>\n \u003cTextAreaComponent \n id='form-textarea'\n placeholder='Your message'\n resizeMode='None'\n rows={5}\n width='100%'\n />\n \u003c/div>\n\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Flexible Vertical with Fixed Width\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='editor-pane'>\n \u003cTextAreaComponent \n id='editor'\n placeholder='Code editor'\n resizeMode='Vertical'\n rows={10}\n width='100%'\n cssClass='monospace'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Browser Support\n\n- **Both, Vertical, Horizontal**: Supported in all modern browsers\n- **None**: Removes resize handle by applying CSS `resize: none`\n- **Mobile**: Touch gestures for resizing may vary by browser\n\n## Best Practices\n\n- **Forms**: Use `Vertical` for consistent layout\n- **Text Editors**: Use `Both` for flexibility\n- **Compact UIs**: Use `None` to maintain design\n- **Mobile**: Constrain `Vertical` on small screens\n- **Accessibility**: Ensure resize handles are visible with sufficient contrast\n- **Content**: Plan min/max heights to accommodate typical content\n- **Responsive**: Adjust resize mode based on viewport size\n- **Performance**: Complex layouts may benefit from `None` mode\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9538,"content_sha256":"42d9fbbe6101edabd0b39d872be1bcb9c5c707079c6072da027ed8dfbe53ad42"},{"filename":"references/textarea-rows-columns-sizing.md","content":"# Rows and Columns Sizing in React TextArea Component\n\nControl the visible dimensions of your TextArea using the `rows` and `cols` properties. These attributes define the initial height (in lines) and width (in characters), allowing precise control over layout.\n\n## Rows Property\n\nThe `rows` attribute sets the visible number of lines (vertical height) of the TextArea.\n\n### Basic Row Configuration\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='textarea'\n placeholder='Enter comments'\n rows={5}\n />\n );\n}\n\nexport default App;\n```\n\nThis creates a TextArea that displays 5 lines without scrolling.\n\n### Common Row Sizes\n\n```typescript\n// Compact (3 rows - good for single-line fallback)\n\u003cTextAreaComponent rows={3} />\n\n// Standard (5 rows - good for typical comments)\n\u003cTextAreaComponent rows={5} />\n\n// Medium (8 rows - good for detailed feedback)\n\u003cTextAreaComponent rows={8} />\n\n// Large (10+ rows - for extended content)\n\u003cTextAreaComponent rows={12} />\n```\n\n## Cols Property\n\nThe `cols` attribute sets the visible width of the TextArea, measured in average character widths.\n\n### Basic Column Configuration\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='textarea'\n placeholder='Enter comments'\n cols={50}\n />\n );\n}\n\nexport default App;\n```\n\nThis creates a TextArea with width equivalent to 50 characters.\n\n### Common Column Widths\n\n```typescript\n// Narrow (30 cols - mobile friendly)\n\u003cTextAreaComponent cols={30} />\n\n// Standard (40 cols - good balance)\n\u003cTextAreaComponent cols={40} />\n\n// Wide (60 cols - full screen on desktop)\n\u003cTextAreaComponent cols={60} />\n\n// Extra wide (80 cols - professional/code)\n\u003cTextAreaComponent cols={80} />\n```\n\n## Combined Rows and Columns\n\n### Multiple TextArea Sizes\n\nCreate different sized textareas for various use cases:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv className='wrap'>\n \u003cdiv className='textarea-group'>\n \u003ch4>Small Comment Box\u003c/h4>\n \u003cTextAreaComponent \n id='small'\n placeholder='Quick comment'\n rows={3}\n cols={35}\n />\n \u003c/div>\n\n \u003cdiv className='textarea-group'>\n \u003ch4>Medium Feedback Form\u003c/h4>\n \u003cTextAreaComponent \n id='medium'\n placeholder='Your feedback'\n rows={5}\n cols={40}\n />\n \u003c/div>\n\n \u003cdiv className='textarea-group'>\n \u003ch4>Large Essay Area\u003c/h4>\n \u003cTextAreaComponent \n id='large'\n placeholder='Write your essay'\n rows={10}\n cols={60}\n />\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Responsive Sizing\n\n### Mobile vs Desktop\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isMobile, setIsMobile] = useState(window.innerWidth \u003c 768);\n\n useEffect(() => {\n const handleResize = () => {\n setIsMobile(window.innerWidth \u003c 768);\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n return (\n \u003cTextAreaComponent \n id='responsive'\n placeholder='Responsive textarea'\n rows={isMobile ? 4 : 8}\n cols={isMobile ? 25 : 50}\n />\n );\n}\n\nexport default App;\n```\n\n## Dynamic Sizing\n\n### Adjust Size Based on Content\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [rows, setRows] = useState(3);\n const [content, setContent] = useState('');\n\n const handleInput = (args) => {\n const value = args.value || '';\n setContent(value);\n \n // Increase rows as content grows\n const lineCount = (value.match(/\\n/g) || []).length + 1;\n setRows(Math.max(3, lineCount + 1));\n };\n\n return (\n \u003cTextAreaComponent \n id='auto-expand'\n value={content}\n input={handleInput}\n placeholder='Type to expand'\n rows={rows}\n cols={40}\n />\n );\n}\n\nexport default App;\n```\n\n### Fixed Size with Scrollbars\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='scrollable'\n placeholder='Fixed size with scrollbars'\n rows={5}\n cols={40}\n resizeMode='None'\n />\n );\n}\n\nexport default App;\n```\n\n## Combining with Other Properties\n\n### With Floating Label\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='textarea'\n placeholder='Enter your feedback'\n floatLabelType='Auto'\n rows={6}\n cols={45}\n />\n );\n}\n\nexport default App;\n```\n\n### With Max Length\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='limited'\n placeholder='Enter comments (max 500 chars)'\n rows={5}\n cols={40}\n maxLength={500}\n />\n );\n}\n\nexport default App;\n```\n\n### With Resize Control\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='resizable'\n placeholder='Resizable textarea'\n rows={4}\n cols={35}\n resizeMode='Both'\n />\n );\n}\n\nexport default App;\n```\n\n## CSS-Based Width Override\n\nWhile `cols` controls the default width, you can override it with CSS:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='custom-width'\n placeholder='Custom width via CSS'\n rows={5}\n cols={40}\n cssClass='full-width'\n />\n );\n}\n\nexport default App;\n```\n\nWith CSS:\n\n```css\n.full-width.e-field {\n width: 100%;\n}\n```\n\n## Sizing Best Practices\n\n### Form Field Layout\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cform className='feedback-form'>\n \u003cdiv className='form-group'>\n \u003clabel>Name\u003c/label>\n \u003cinput type='text' />\n \u003c/div>\n\n \u003cdiv className='form-group'>\n \u003clabel>Email\u003c/label>\n \u003cinput type='email' />\n \u003c/div>\n\n \u003cdiv className='form-group'>\n \u003clabel>Feedback\u003c/label>\n \u003cTextAreaComponent \n id='feedback'\n placeholder='Your feedback'\n rows={6}\n cols={50}\n floatLabelType='Auto'\n />\n \u003c/div>\n\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n### Different Purposes\n\n```typescript\n// Chat message input\n\u003cTextAreaComponent rows={3} cols={40} />\n\n// Bug report form\n\u003cTextAreaComponent rows={8} cols={60} />\n\n// Review submission\n\u003cTextAreaComponent rows={6} cols={50} />\n\n// Code snippet area\n\u003cTextAreaComponent rows={10} cols={80} />\n\n// Social media post\n\u003cTextAreaComponent rows={4} cols={45} />\n```\n\n## Width Property Alternative\n\nFor more precise width control, use the `width` property instead of `cols`:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='precise-width'\n placeholder='Width in pixels'\n rows={5}\n width='400px'\n />\n );\n}\n\nexport default App;\n```\n\nOr percentage-based width:\n\n```typescript\n\u003cTextAreaComponent \n id='responsive-width'\n placeholder='Full container width'\n rows={5}\n width='100%'\n/>\n```\n\n## Considerations\n\n- **Browser Support**: `rows` and `cols` are standard HTML attributes, supported in all browsers\n- **Character Width**: `cols` is based on monospace character width; actual visible width varies with fonts\n- **Mobile**: Reduce `cols` for mobile devices (25-30) vs desktop (40-60)\n- **Accessibility**: Provide appropriate sizing for keyboard users\n- **Scrollbars**: Long content will scroll if it exceeds the visible area\n- **Resizing**: Use `resizeMode` property to control user resizing capability\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8826,"content_sha256":"48082700a229f37222e146967a26af2566dc1a549834d9f240d66007db336f57"},{"filename":"references/textarea-styling-appearance.md","content":"# Styling and Appearance in React TextArea Component\n\n## Table of Contents\n- [Size Classes](#size-classes)\n- [Filled and Outline Modes](#filled-and-outline-modes)\n- [Custom CSS](#custom-css)\n- [Disabled and Read-Only States](#disabled-and-read-only-states)\n- [Validation States](#validation-states)\n- [Clear Button](#clear-button)\n- [Color Customization](#color-customization)\n- [Advanced Styling](#advanced-styling)\n\n## Size Classes\n\nApply size variations using CSS classes to adjust the TextArea appearance.\n\n### Small TextArea\n\nAdd the `e-small` class for a compact textarea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003ch4>Small TextArea\u003c/h4>\n \u003cdiv className='e-input-group e-small'>\n \u003ctextarea \n className='e-input' \n placeholder='Small textarea'\n >\u003c/textarea>\n \u003c/div>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\nWith TextAreaComponent:\n\n```typescript\n\u003cTextAreaComponent \n id='small'\n placeholder='Small textarea'\n cssClass='e-small'\n/>\n```\n\n### Bigger TextArea\n\nAdd the `e-bigger` class for an enlarged textarea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='bigger'\n placeholder='Bigger textarea'\n cssClass='e-bigger'\n />\n );\n}\n\nexport default App;\n```\n\n### Normal TextArea (Default)\n\nNo class needed - default size applies automatically.\n\n## Filled and Outline Modes\n\nSyncfusion TextArea supports two appearance modes: filled and outline. These are available with Material themes.\n\n### Outline Mode\n\nThe outline style displays a border around the textarea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='outlined'\n placeholder='Outlined'\n floatLabelType='Auto'\n cssClass='e-outline'\n />\n );\n}\n\nexport default App;\n```\n\n### Filled Mode\n\nThe filled style displays a background color with the textarea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='filled'\n placeholder='Filled'\n floatLabelType='Auto'\n cssClass='e-filled'\n />\n );\n}\n\nexport default App;\n```\n\n### Combining Size and Mode\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='small-outline'\n placeholder='Small outline'\n cssClass='e-small e-outline'\n floatLabelType='Auto'\n />\n\n \u003cTextAreaComponent \n id='big-filled'\n placeholder='Bigger filled'\n cssClass='e-bigger e-filled'\n floatLabelType='Auto'\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Custom CSS\n\nApply custom styling using the `cssClass` property:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='custom'\n placeholder='Enter comments'\n floatLabelType='Auto'\n cssClass='custom-textarea'\n />\n );\n}\n\nexport default App;\n```\n\nWith CSS:\n\n```css\n.custom-textarea.e-field {\n background-color: #f5f5f5;\n border-color: #2196F3;\n border-radius: 8px;\n}\n\n.custom-textarea.e-field:focus {\n background-color: #ffffff;\n box-shadow: 0 0 8px rgba(33, 150, 243, 0.3);\n}\n```\n\n## Disabled and Read-Only States\n\n### Disabled State\n\nPrevent user interaction using the `enabled` property:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='disabled'\n placeholder='This is disabled'\n enabled={false}\n />\n );\n}\n\nexport default App;\n```\n\nThe disabled textarea appears grayed out and cannot be interacted with.\n\n### Read-Only State\n\nPrevent editing but allow selection using the `readonly` property:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='readonly'\n value='This content cannot be edited'\n readonly={true}\n />\n );\n}\n\nexport default App;\n```\n\nUsers can select and copy read-only content but cannot edit it.\n\n### Toggle States\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [isEnabled, setIsEnabled] = useState(true);\n\n return (\n \u003cdiv>\n \u003cbutton onClick={() => setIsEnabled(!isEnabled)}>\n {isEnabled ? 'Disable' : 'Enable'}\n \u003c/button>\n\n \u003cTextAreaComponent \n id='togglable'\n placeholder='Toggle enabled state'\n enabled={isEnabled}\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Validation States\n\nApply validation styling using CSS classes:\n\n### Success State\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='success'\n placeholder='Valid input'\n cssClass='e-success'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Warning State\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='warning'\n placeholder='Warning state'\n cssClass='e-warning'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Error State\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='error'\n placeholder='Error input'\n cssClass='e-error'\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n### Dynamic Validation Styling\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const getValidationClass = () => {\n if (text.length === 0) return '';\n if (text.length \u003c 10) return 'e-warning';\n return 'e-success';\n };\n\n return (\n \u003cTextAreaComponent \n id='validated'\n value={text}\n input={(args) => setText(args.value || '')}\n placeholder='Type to validate'\n cssClass={getValidationClass()}\n floatLabelType='Auto'\n />\n );\n}\n\nexport default App;\n```\n\n## Clear Button\n\nDisplay a button to clear textarea content:\n\n### Static Clear Button\n\nShow clear button always:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='clearable'\n placeholder='Enter text'\n showClearButton={true}\n cssClass='e-static-clear'\n />\n );\n}\n\nexport default App;\n```\n\n### Conditional Clear Button\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [text, setText] = useState('');\n\n return (\n \u003cTextAreaComponent \n id='conditional-clear'\n value={text}\n input={(args) => setText(args.value || '')}\n placeholder='Enter text'\n showClearButton={text.length > 0}\n />\n );\n}\n\nexport default App;\n```\n\n## Color Customization\n\n### Background and Text Color\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='styled'\n placeholder='Custom colors'\n cssClass='custom-colors'\n />\n );\n}\n\nexport default App;\n```\n\nCSS:\n\n```css\n.custom-colors.e-field {\n background-color: #fff8f0;\n color: #333333;\n}\n\n.custom-colors.e-field::placeholder {\n color: #999999;\n}\n\n.custom-colors.e-field:focus {\n background-color: #fffaf7;\n border-color: #ff6b35;\n}\n```\n\n### Floating Label Color\n\nChange floating label color for validation states:\n\n```css\n/* Success state floating label */\n.e-float-input.e-success label.e-float-text,\n.e-float-input.e-success textarea:focus ~ label.e-float-text {\n color: #22b24b;\n}\n\n/* Warning state floating label */\n.e-float-input.e-warning label.e-float-text,\n.e-float-input.e-warning textarea:focus ~ label.e-float-text {\n color: #ffca1c;\n}\n\n/* Error state floating label */\n.e-float-input.e-error label.e-float-text,\n.e-float-input.e-error textarea:focus ~ label.e-float-text {\n color: #d32f2f;\n}\n```\n\n## Advanced Styling\n\n### Rounded Corners\n\nAdd rounded corners by applying the `e-corner` class:\n\n```typescript\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cdiv className='e-input-group e-corner'>\n \u003ctextarea \n className='e-input'\n placeholder='Rounded corners'\n >\u003c/textarea>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Custom Font and Spacing\n\n```css\n.custom-textarea.e-field {\n font-family: 'Monaco', 'Menlo', monospace;\n font-size: 14px;\n line-height: 1.6;\n padding: 12px 16px;\n}\n```\n\n### Focus Effects\n\n```css\n.custom-textarea.e-field {\n transition: all 0.3s ease;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.custom-textarea.e-field:focus {\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.2);\n transform: translateY(-2px);\n}\n```\n\n### Mandatory Asterisk\n\nAdd asterisk to placeholder for required fields:\n\n```css\n.e-float-input.e-control-wrapper .e-float-text::after {\n content: '*';\n color: red;\n margin-left: 4px;\n}\n```\n\nWith TextArea:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='required'\n placeholder='Your comments'\n floatLabelType='Auto'\n cssClass='required-field'\n />\n );\n}\n\nexport default App;\n```\n\n### Disabled Appearance\n\n```css\n.e-input:disabled,\n.e-field:disabled {\n background-color: #f5f5f5;\n color: #9e9e9e;\n cursor: not-allowed;\n opacity: 0.6;\n}\n```\n\n## Complete Themed Example\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [text, setText] = useState('');\n const [theme, setTheme] = useState('light');\n\n const getThemeClass = () => {\n return theme === 'dark' ? 'textarea-dark' : 'textarea-light';\n };\n\n return (\n \u003cdiv className={getThemeClass()}>\n \u003cbutton onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>\n Toggle Theme\n \u003c/button>\n\n \u003cTextAreaComponent \n id='themed'\n value={text}\n input={(args) => setText(args.value || '')}\n placeholder='Enter text'\n cssClass={`${getThemeClass()} e-outline`}\n floatLabelType='Auto'\n showClearButton={text.length > 0}\n />\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\nCSS:\n\n```css\n/* Light theme */\n.textarea-light.e-field {\n background-color: #ffffff;\n color: #333333;\n border-color: #cccccc;\n}\n\n/* Dark theme */\n.textarea-dark.e-field {\n background-color: #2d2d2d;\n color: #e0e0e0;\n border-color: #555555;\n}\n\n.textarea-dark.e-field::placeholder {\n color: #888888;\n}\n```\n\n## Best Practices\n\n- Use outline mode for modern, clean designs\n- Apply validation classes consistently across forms\n- Ensure sufficient color contrast for accessibility\n- Test styling on different themes (Material, Bootstrap, Tailwind)\n- Use CSS transitions for smooth state changes\n- Maintain consistent sizing across form fields\n- Test disabled/readonly states for visual distinction\n- Document custom CSS classes for team consistency\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12346,"content_sha256":"2f64f3f360ca5171651fc6cd407392b05a093402cf00e9d14731ac9baac9dcb7"},{"filename":"references/textarea-value-and-content.md","content":"# Value and Content Management in React TextArea\n\nEfficiently manage TextArea content by setting initial values, updating content dynamically, and retrieving values for form submission or data processing.\n\n## Setting Initial Values\n\n### Direct Property Binding\n\nSet the initial value using the `value` property when the component renders:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cTextAreaComponent \n id='comments'\n value='Enter your feedback here'\n />\n );\n}\n\nexport default App;\n```\n\n### Using State Variable\n\nFor dynamic initial values or updates, use React state:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [initialComment, setInitialComment] = useState('Please enter your comments');\n\n return (\n \u003cTextAreaComponent \n id='comments'\n value={initialComment}\n />\n );\n}\n\nexport default App;\n```\n\n### Loading Values from Data\n\nFetch and populate initial values from an API or database:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState, useEffect } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [feedbackValue, setFeedbackValue] = useState('');\n\n useEffect(() => {\n // Simulate API call\n const fetchFeedback = async () => {\n const response = await fetch('/api/feedback/123');\n const data = await response.json();\n setFeedbackValue(data.message);\n };\n \n fetchFeedback();\n }, []);\n\n return (\n \u003cTextAreaComponent \n id='feedback'\n value={feedbackValue}\n />\n );\n}\n\nexport default App;\n```\n\n## Getting Current Value\n\n### From State Variable\n\nAccess the current value through the state variable:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [textValue, setTextValue] = useState('');\n\n const handleGetValue = () => {\n console.log('Current textarea value:', textValue);\n return textValue;\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='content'\n value={textValue}\n />\n \u003cbutton onClick={handleGetValue}>Get Value\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### From Component Reference\n\nUse a ref to directly access the component instance:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const textareaRef = useRef(null);\n\n const handleGetValue = () => {\n if (textareaRef.current) {\n const value = textareaRef.current.value;\n console.log('TextArea value from ref:', value);\n return value;\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n ref={textareaRef}\n id='content'\n />\n \u003cbutton onClick={handleGetValue}>Get Value\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Real-Time Change Detection\n\n### Using Input Event\n\nThe `input` event fires every keystroke, providing real-time value updates:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { InputEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('');\n const [charCount, setCharCount] = useState(0);\n\n const handleInput = (args: InputEventArgs) => {\n const value = args.value || '';\n setText(value);\n setCharCount(value.length);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='editor'\n input={handleInput}\n />\n \u003cp>Characters typed: {charCount}\u003c/p>\n \u003cp>Content: {text}\u003c/p>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Using Change Event\n\nThe `change` event fires when focus is lost, useful for form submissions:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport type { ChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [savedValue, setSavedValue] = useState('');\n\n const handleChange = (args: ChangedEventArgs) => {\n setSavedValue(args.value || '');\n console.log('Value saved on blur:', args.value);\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='notes'\n change={handleChange}\n />\n \u003cp>Last saved: {savedValue}\u003c/p>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Updating Content Dynamically\n\n### Update from External Events\n\nChange textarea content in response to user actions:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const handleLoadTemplate = () => {\n setText('Dear User,\\nThank you for your feedback.\\nBest regards');\n };\n\n const handleClear = () => {\n setText('');\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='message'\n value={text}\n />\n \u003cbutton onClick={handleLoadTemplate}>Load Template\u003c/button>\n \u003cbutton onClick={handleClear}>Clear\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Append Text\n\nAdd text to existing content:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('Initial text\\n');\n\n const handleAppend = () => {\n setText(prev => prev + 'New line added\\n');\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='document'\n value={text}\n />\n \u003cbutton onClick={handleAppend}>Add Line\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Replace All Text\n\nCompletely replace textarea content:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const handleReplace = () => {\n setText('This is completely new content');\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='editor'\n value={text}\n />\n \u003cbutton onClick={handleReplace}>Replace All\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Form Submission\n\n### Get Value for Form Submit\n\nCollect textarea value when form is submitted:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [formData, setFormData] = useState({\n name: '',\n comments: ''\n });\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n console.log('Form submitted with:', formData);\n // Send to API\n };\n\n return (\n \u003cform onSubmit={handleSubmit}>\n \u003cinput \n type='text'\n placeholder='Name'\n value={formData.name}\n onChange={(e) => setFormData({...formData, name: e.target.value})}\n />\n \u003cTextAreaComponent \n id='comments'\n value={formData.comments}\n input={(args) => setFormData({...formData, comments: args.value || ''})}\n />\n \u003cbutton type='submit'>Submit\u003c/button>\n \u003c/form>\n );\n}\n\nexport default App;\n```\n\n## Content Transformation\n\n### Transform and Update\n\nApply transformations to content while editing:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const handleToUpperCase = () => {\n setText(text.toUpperCase());\n };\n\n const handleToLowerCase = () => {\n setText(text.toLowerCase());\n };\n\n const handleTrim = () => {\n setText(text.trim());\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='text-editor'\n value={text}\n input={(args) => setText(args.value || '')}\n />\n \u003cbutton onClick={handleToUpperCase}>UPPERCASE\u003c/button>\n \u003cbutton onClick={handleToLowerCase}>lowercase\u003c/button>\n \u003cbutton onClick={handleTrim}>Trim\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n## Empty State Handling\n\n### Check if Empty\n\nValidate before submission:\n\n```typescript\nimport { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport * as React from 'react';\n\nfunction App() {\n const [text, setText] = useState('');\n\n const handleValidate = () => {\n if (!text || text.trim() === '') {\n console.log('TextArea is empty');\n return false;\n }\n console.log('TextArea has content');\n return true;\n };\n\n return (\n \u003cdiv>\n \u003cTextAreaComponent \n id='feedback'\n value={text}\n input={(args) => setText(args.value || '')}\n />\n \u003cbutton onClick={handleValidate}>Validate\u003c/button>\n \u003c/div>\n );\n}\n\nexport default App;\n```\n\n### Default Values\n\nProvide fallback values:\n\n```typescript\nconst getTextValue = (value: string | undefined | null): string => {\n return (value || 'No content provided').trim();\n};\n```\n\n## Best Practices\n\n- **Always manage state** for controlled components\n- **Use `input` event** for real-time tracking\n- **Use `change` event** for form submissions\n- **Validate empty content** before processing\n- **Transform text** safely with proper null checks\n- **Keep refs minimal** - prefer state management\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9588,"content_sha256":"4e41d6baef8017817bf80131eb79be3170815334cdbc6806e77a8c4285257c98"},{"filename":"references/textbox-accessibility-and-migration.md","content":"# Accessibility and Migration\n\n## Table of Contents\n\n- [Accessibility Overview](#accessibility-overview)\n- [WCAG and Standards Compliance](#wcag-and-standards-compliance)\n- [WAI-ARIA Implementation](#wai-aria-implementation)\n- [Screen Reader Support](#screen-reader-support)\n- [Keyboard Navigation](#keyboard-navigation)\n- [Right-to-Left Support](#right-to-left-support)\n- [Migration from CSS TextBox](#migration-from-css-textbox)\n\n## Accessibility Overview\n\nThe Syncfusion React TextBox component is built with accessibility as a core feature, enabling all users—including those using assistive technologies—to interact effectively. The component complies with:\n\n- **WCAG 2.2** - Web Content Accessibility Guidelines Level AA\n- **Section 508** - U.S. Federal accessibility requirement\n- **WAI-ARIA** - Web Accessibility Initiative Accessible Rich Internet Applications\n- **Mobile devices** - Touch-friendly, accessible on all devices\n\n### Accessibility Compliance Matrix\n\n| Criterion | Support |\n|-----------|---------|\n| WCAG 2.2 | ✓ Full compliance |\n| Section 508 | ✓ Full compliance |\n| Screen Readers | ✓ Full support |\n| RTL Support | ✓ Full support |\n| Color Contrast | ✓ WCAG AA standard |\n| Mobile Support | ✓ Touch-optimized |\n| Keyboard Navigation | ✓ Full support |\n| Accessibility Checker | ✓ Validated |\n| Axe-core | ✓ Validated |\n\n## WCAG and Standards Compliance\n\n### Color Contrast\n\nTextBox components meet WCAG AA standards for color contrast (4.5:1 minimum for normal text, 3:1 for large text).\n\n**Ensure proper contrast in custom CSS:**\n\n```css\n/* Good: High contrast */\n.e-input {\n background-color: #FFFFFF;\n color: #000000; /* 21:1 contrast ratio */\n}\n\n/* Avoid: Low contrast */\n.e-input {\n background-color: #F8F8F8;\n color: #E8E8E8; /* Too low contrast */\n}\n```\n\n### Text Sizing\n\nProvide readable font sizes:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function AccessibleTextBox() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Minimum 16px on mobile\"\n floatLabelType=\"Auto\"\n style={{ fontSize: '16px' }} // Prevents mobile zoom-on-focus\n />\n );\n}\n```\n\n### Focus Indicators\n\nEnsure visible focus indicators for keyboard users:\n\n```css\n.e-input:focus,\n.e-float-input input:focus {\n outline: 3px solid #2196F3;\n outline-offset: 2px;\n}\n```\n\n## WAI-ARIA Implementation\n\n### ARIA Attributes\n\nThe TextBox automatically implements WAI-ARIA attributes:\n\n| Attribute | Value | Purpose |\n|-----------|-------|---------|\n| `role` | `textbox` | Identifies element as textbox |\n| `aria-placeholder` | text | Short hint when empty |\n| `aria-labelledby` | id | Links to floating label |\n| `aria-invalid` | true/false | Indicates validation state |\n| `aria-describedby` | id | Links to error message |\n\n### Manual ARIA Implementation\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function AccessibleTextBox() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n return (\n \u003c>\n \u003clabel id=\"name-label\" htmlFor=\"name-input\">\n Full Name *\n \u003c/label>\n \n \u003cTextBoxComponent\n id=\"name-input\"\n ref={textboxRef}\n placeholder=\"Enter your full name\"\n floatLabelType=\"Auto\"\n htmlAttributes={{\n 'aria-labelledby': 'name-label',\n 'aria-required': 'true',\n 'aria-describedby': 'name-error'\n }}\n />\n\n \u003cdiv id=\"name-error\" role=\"alert\">\n {/* Error message appears here */}\n \u003c/div>\n \u003c/>\n );\n}\n```\n\n### Error Messages with ARIA\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function AccessibleValidation() {\n const [email, setEmail] = useState('');\n const [error, setError] = useState('');\n\n const handleChange = (e: any) => {\n const value = e.value;\n setEmail(value);\n\n // Validate and set error\n if (value && !value.includes('@')) {\n setError('Email must contain @ symbol');\n } else {\n setError('');\n }\n };\n\n return (\n \u003c>\n \u003clabel htmlFor=\"email-input\">Email Address *\u003c/label>\n \n \u003cTextBoxComponent\n id=\"email-input\"\n type=\"email\"\n placeholder=\"[email protected]\"\n floatLabelType=\"Auto\"\n value={email}\n change={handleChange}\n cssClass={error ? 'e-error' : ''}\n htmlAttributes={{\n 'aria-invalid': error ? 'true' : 'false',\n ...(error ? { 'aria-describedby': 'email-error' } : {})\n }}\n />\n\n {error && (\n \u003cdiv id=\"email-error\" role=\"alert\" style={{ color: '#F44336', marginTop: '5px' }}>\n {error}\n \u003c/div>\n )}\n \u003c/>\n );\n}\n```\n\n## Screen Reader Support\n\n### Proper Labeling\n\nAlways provide explicit labels for TextBox inputs:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ScreenReaderFriendly() {\n return (\n \u003cdiv>\n \u003clabel htmlFor=\"username\">Username\u003c/label>\n \u003cTextBoxComponent\n id=\"username\"\n placeholder=\"Enter your username\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n );\n}\n```\n\n**Screen reader announces:** \"Username, input field, placeholder: Enter your username\"\n\n### Form Legends\n\nGroup related inputs with `\u003cfieldset>` and `\u003clegend>`:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function AccessibleForm() {\n return (\n \u003cform>\n \u003cfieldset>\n \u003clegend>Personal Information\u003c/legend>\n\n \u003cdiv>\n \u003clabel htmlFor=\"first-name\">First Name *\u003c/label>\n \u003cTextBoxComponent\n id=\"first-name\"\n placeholder=\"First name\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ 'aria-required': 'true' }}\n />\n \u003c/div>\n\n \u003cdiv>\n \u003clabel htmlFor=\"last-name\">Last Name *\u003c/label>\n \u003cTextBoxComponent\n id=\"last-name\"\n placeholder=\"Last name\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ 'aria-required': 'true' }}\n />\n \u003c/div>\n \u003c/fieldset>\n\n \u003cfieldset>\n \u003clegend>Contact Information\u003c/legend>\n\n \u003cdiv>\n \u003clabel htmlFor=\"email\">Email *\u003c/label>\n \u003cTextBoxComponent\n id=\"email\"\n type=\"email\"\n placeholder=\"[email protected]\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ 'aria-required': 'true' }}\n />\n \u003c/div>\n \u003c/fieldset>\n \u003c/form>\n );\n}\n```\n\n### Helper Text and Instructions\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function HelpfulTextBox() {\n return (\n \u003cdiv>\n \u003clabel htmlFor=\"password\">Password\u003c/label>\n \n \u003cp id=\"password-hint\" style={{ fontSize: '14px', color: '#666' }}>\n Must be at least 8 characters with letters and numbers\n \u003c/p>\n\n \u003cTextBoxComponent\n id=\"password\"\n type=\"password\"\n placeholder=\"Enter your password\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ 'aria-describedby': 'password-hint' }}\n />\n \u003c/div>\n );\n}\n```\n\n## Keyboard Navigation\n\n### Tab Order\n\nTextBox is automatically part of the tab order:\n\n```tsx\n\u003cform>\n \u003cTextBoxComponent placeholder=\"First field\" floatLabelType=\"Auto\" />\n \u003cTextBoxComponent placeholder=\"Second field\" floatLabelType=\"Auto\" />\n \u003cTextBoxComponent placeholder=\"Third field\" floatLabelType=\"Auto\" />\n {/* Tab order: 1 → 2 → 3 */}\n\u003c/form>\n```\n\n### Keyboard Events\n\nUse the native `htmlAttributes` property to attach keyboard event handlers via standard HTML attributes, or wrap the TextBoxComponent in a container with `onKeyDown`:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function KeyboardSupport() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleKeyDown = (e: React.KeyboardEvent\u003cHTMLDivElement>) => {\n if (e.key === 'Enter') {\n console.log('Enter pressed');\n }\n if (e.key === 'Escape') {\n console.log('Escape pressed');\n if (textboxRef.current) {\n textboxRef.current.value = '';\n }\n }\n };\n\n return (\n \u003cdiv onKeyDown={handleKeyDown}>\n \u003cTextBoxComponent\n placeholder=\"Press Enter or Escape\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n />\n \u003c/div>\n );\n}\n```\n\n### Focus Management\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useEffect } from 'react';\n\nexport default function FocusManagement() {\n const firstInputRef = useRef\u003cTextBoxComponent>(null);\n const secondInputRef = useRef\u003cTextBoxComponent>(null);\n\n useEffect(() => {\n // Auto-focus first input on mount\n firstInputRef.current?.focusIn();\n }, []);\n\n return (\n \u003cform>\n \u003cdiv>\n \u003clabel htmlFor=\"input1\">First Input\u003c/label>\n \u003cTextBoxComponent\n id=\"input1\"\n ref={firstInputRef}\n placeholder=\"Tab to next field\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n \u003cdiv>\n \u003clabel htmlFor=\"input2\">Second Input\u003c/label>\n \u003cTextBoxComponent\n id=\"input2\"\n ref={secondInputRef}\n placeholder=\"Second field\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n \u003c/form>\n );\n}\n```\n\n## Right-to-Left Support\n\n### Enable RTL\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function RTLTextBox() {\n return (\n \u003cdiv dir=\"rtl\">\n \u003clabel htmlFor=\"arabic-input\">الاسم (Name)\u003c/label>\n \u003cTextBoxComponent\n id=\"arabic-input\"\n placeholder=\"أدخل اسمك\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n );\n}\n```\n\n### RTL with CSS\n\n```css\n[dir=\"rtl\"] .e-input-group,\n[dir=\"rtl\"] .e-float-input {\n direction: rtl;\n text-align: right;\n}\n\n[dir=\"rtl\"] .e-input {\n direction: rtl;\n}\n```\n\n## Migration from CSS TextBox\n\n### Before: CSS TextBox\n\nTraditional approach using HTML and CSS:\n\n```html\n\u003c!-- Normal TextBox -->\n\u003cdiv class=\"e-input-group\">\n \u003cinput class=\"e-input\" type=\"text\" placeholder=\"Enter Value\" />\n\u003c/div>\n\n\u003c!-- Floating Label TextBox -->\n\u003cdiv class=\"e-float-input\">\n \u003cinput type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Enter Value\u003c/label>\n\u003c/div>\n\n\u003c!-- TextBox with clear button (manual JavaScript required) -->\n\u003cdiv class=\"e-input-group\">\n \u003cinput class=\"e-input\" type=\"text\" placeholder=\"Enter Value\" required />\n \u003cspan class=\"e-clear-icon\">\u003c/span>\n\u003c/div>\n```\n\n**Disadvantages:**\n- Manual DOM manipulation required\n- No built-in event handling\n- Duplicate HTML structure\n- More CSS code needed\n- Error handling requires JavaScript\n\n### After: React TextBox Component\n\nModern approach using React component:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\n// Normal TextBox\n\u003cTextBoxComponent \n placeholder=\"Enter Value\"\n floatLabelType=\"Never\"\n/>\n\n// Floating Label TextBox\n\u003cTextBoxComponent \n placeholder=\"Enter Value\"\n floatLabelType=\"Auto\"\n/>\n\n// TextBox with clear button\n\u003cTextBoxComponent \n placeholder=\"Enter Value\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n/>\n```\n\n**Advantages:**\n- ✓ Built-in functionality\n- ✓ Automatic event handling\n- ✓ Cleaner syntax\n- ✓ Less code duplication\n- ✓ Better accessibility\n- ✓ Easier state management\n\n### Migration Comparison\n\n#### Normal Input\n\n**CSS Version:**\n```html\n\u003cdiv class=\"e-input-group\">\n \u003cinput class=\"e-input\" type=\"text\" placeholder=\"Enter Name\" />\n\u003c/div>\n```\n\n**React Version:**\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Enter Name\"\n floatLabelType=\"Never\"\n/>\n```\n\n**Benefit:** 1 line vs 3 lines (67% reduction)\n\n#### Floating Label Input\n\n**CSS Version:**\n```html\n\u003cdiv class=\"e-float-input\">\n \u003cinput type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Enter Name\u003c/label>\n\u003c/div>\n```\n\n**React Version:**\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Enter Name\"\n floatLabelType=\"Auto\"\n/>\n```\n\n**Benefit:** 1 line vs 5 lines (80% reduction)\n\n#### Clear Button\n\n**CSS Version:**\n```html\n\u003cdiv class=\"e-float-input e-input-group\">\n \u003cinput type=\"text\" required value=\"Clear Input\" />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Enter Value\u003c/label>\n \u003cspan class=\"e-clear-icon\">\u003c/span>\n\u003c/div>\n\u003c!-- JavaScript required for clear button functionality -->\n\u003cscript>\n document.querySelector('.e-clear-icon').addEventListener('click', function() {\n document.querySelector('input').value = '';\n });\n\u003c/script>\n```\n\n**React Version:**\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Enter Value\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n/>\n```\n\n**Benefit:** 1 line vs 10+ lines with JavaScript\n\n#### Validation States\n\n**CSS Version:**\n```html\n\u003c!-- Error state -->\n\u003cdiv class=\"e-float-input e-error\">\n \u003cinput type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Email\u003c/label>\n\u003c/div>\n\n\u003c!-- Warning state -->\n\u003cdiv class=\"e-float-input e-warning\">\n \u003cinput type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Email\u003c/label>\n\u003c/div>\n\n\u003c!-- Success state -->\n\u003cdiv class=\"e-float-input e-success\">\n \u003cinput type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Email\u003c/label>\n\u003c/div>\n```\n\n**React Version:**\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n cssClass=\"e-error\"\n/>\n\n\u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n cssClass=\"e-warning\"\n/>\n\n\u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n cssClass=\"e-success\"\n/>\n```\n\n### Complete Migration Example\n\n**Before (CSS TextBox):**\n\n```html\n\u003c!DOCTYPE html>\n\u003chtml>\n\u003chead>\n \u003clink rel=\"stylesheet\" href=\"ej2.css\">\n\u003c/head>\n\u003cbody>\n \u003cdiv class=\"e-float-input\">\n \u003cinput id=\"name\" type=\"text\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Name\u003c/label>\n \u003c/div>\n\n \u003cdiv class=\"e-float-input\">\n \u003cinput id=\"email\" type=\"email\" required />\n \u003cspan class=\"e-float-line\">\u003c/span>\n \u003clabel class=\"e-float-text\">Email\u003c/label>\n \u003c/div>\n\n \u003cbutton onclick=\"submitForm()\">Submit\u003c/button>\n\n \u003cscript>\n function submitForm() {\n const name = document.getElementById('name').value;\n const email = document.getElementById('email').value;\n console.log('Form:', { name, email });\n }\n \u003c/script>\n\u003c/body>\n\u003c/html>\n```\n\n**After (React TextBox):**\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function App() {\n const [formData, setFormData] = useState({ name: '', email: '' });\n\n const handleSubmit = () => {\n console.log('Form:', formData);\n };\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n placeholder=\"Name\"\n floatLabelType=\"Auto\"\n value={formData.name}\n change={(e) => setFormData({ ...formData, name: e.value })}\n />\n\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n type=\"email\"\n value={formData.email}\n change={(e) => setFormData({ ...formData, email: e.value })}\n />\n\n \u003cbutton onClick={handleSubmit}>Submit\u003c/button>\n \u003c/div>\n );\n}\n```\n\n**Code Reduction:** ~50% less code\n\n## See Also\n\n- [Getting Started](./getting-started.md) - Setup and installation\n- [Features and Groups](./features-and-groups.md) - Floating labels and icons\n- [Validation and States](./validation-and-states.md) - Input validation\n- [Advanced Features](./advanced-features.md) - React hooks integration\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15587,"content_sha256":"59429c6ccb8c03918c39ce63e2970d82e211a7643874ceeb30522e9397a3e5e7"},{"filename":"references/textbox-advanced-features.md","content":"# Advanced Features\n\n## Table of Contents\n\n- [Adornments](#adornments)\n- [Prepend and Append Templates](#prepend-and-append-templates)\n- [React Hooks Integration](#react-hooks-integration)\n- [Event Handling](#event-handling)\n- [Form Integration](#form-integration)\n\n## Adornments\n\nAdornments are visual or interactive elements added before (prepend) or after (append) the TextBox input. Use templates to add custom icons, buttons, text labels, or interactive controls.\n\n### Prepend Template\n\nAdd content before the input using `prependTemplate`. The template function must return `JSX.Element`:\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function PrependExample() {\n function prependIcon(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-icons e-user\">\u003c/span>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter username\"\n floatLabelType=\"Auto\"\n prependTemplate={prependIcon}\n />\n );\n}\n```\n\n**Result:**\n```\n┌──────────────────────────┐\n│ 👤 | Enter username │\n└──────────────────────────┘\n```\n\n### Append Template\n\nAdd content after the input using `appendTemplate`. The template function must return `JSX.Element`:\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function AppendExample() {\n function appendButton(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan className=\"e-icons e-input-popup-date\">\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Select date\"\n floatLabelType=\"Auto\"\n appendTemplate={appendButton}\n />\n );\n}\n```\n\n**Result:**\n```\n┌──────────────────────────┐\n│ Select date 📅 |\n└──────────────────────────┘\n```\n\n## Prepend and Append Templates\n\n### Interactive Adornment: Password Visibility Toggle\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useState } from 'react';\n\nexport default function PasswordToggle() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n const [isVisible, setIsVisible] = useState(false);\n\n const toggleVisibility = () => {\n if (textboxRef.current) {\n const newVisibility = !isVisible;\n textboxRef.current.type = newVisibility ? 'text' : 'password';\n setIsVisible(newVisibility);\n }\n };\n\n function appendToggle(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan\n className={`e-icons ${isVisible ? 'e-eye-slash' : 'e-eye'}`}\n onClick={toggleVisibility}\n style={{ cursor: 'pointer' }}\n >\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n type=\"password\"\n placeholder=\"Enter password\"\n floatLabelType=\"Auto\"\n appendTemplate={appendToggle}\n />\n );\n}\n```\n\n### Interactive Adornment: Clear Button\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useState } from 'react';\n\nexport default function ClearButton() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n const [value, setValue] = useState('');\n\n const handleClear = () => {\n if (textboxRef.current) {\n textboxRef.current.value = '';\n setValue('');\n }\n };\n\n function appendClear(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan\n className=\"e-icons e-trash\"\n onClick={handleClear}\n style={{ cursor: 'pointer' }}\n >\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"Text to clear\"\n floatLabelType=\"Auto\"\n value={value}\n change={(e) => setValue(e.value)}\n appendTemplate={value ? appendClear : undefined}\n />\n );\n}\n```\n\n### Complex Adornment: Email with Domain\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function EmailWithDomain() {\n const [domain, setDomain] = useState('gmail.com');\n\n function prependEmail(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-icons e-input-popup-date\">\u003c/span>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003c/>\n );\n }\n\n function appendDomain(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan style={{ padding: '0 8px', color: '#666' }}>@{domain}\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cdiv>\n \u003cdiv style={{ marginBottom: '15px' }}>\n \u003clabel>Select Domain:\u003c/label>\n \u003cselect \n value={domain} \n onChange={(e) => setDomain(e.target.value)}\n style={{ padding: '8px', marginLeft: '10px' }}\n >\n \u003coption>gmail.com\u003c/option>\n \u003coption>outlook.com\u003c/option>\n \u003coption>yahoo.com\u003c/option>\n \u003coption>company.com\u003c/option>\n \u003c/select>\n \u003c/div>\n\n \u003cTextBoxComponent\n placeholder=\"username\"\n floatLabelType=\"Auto\"\n prependTemplate={prependEmail}\n appendTemplate={appendDomain}\n />\n \u003c/div>\n );\n}\n```\n\n### Multi-Element Adornment: Complex Form Input\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function CurrencyInput() {\n const [value, setValue] = useState('');\n const [currency, setCurrency] = useState('USD');\n\n function prependCurrency(): JSX.Element {\n return (\n \u003c>\n \u003cspan style={{ padding: '0 8px', color: '#666', fontWeight: 'bold' }}>\n {currency === 'USD' ? '

Implementing Syncfusion React Inputs Uploader The Syncfusion React UploaderComponent provides a rich file upload control with async upload, drag-and-drop, chunk upload with pause/resume/cancel, validation, templates, form integration, and accessibility support. Navigation Guide 🛑 Agentic use: Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation). Getting Started 📄 Read: references/getting-started.md - Installing 🛑 STOP — Do not install packages autonomously. Ask the user to run: . Verify with - License registration - Basic usage…

: currency === 'EUR' ? '€' : '£'}\n \u003c/span>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003c/>\n );\n }\n\n function appendCurrency(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan style={{ padding: '0 8px', color: '#999', fontSize: '12px' }}>\n {currency}\n \u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cdiv>\n \u003cdiv style={{ marginBottom: '15px' }}>\n \u003clabel>Currency:\u003c/label>\n \u003cselect \n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n style={{ padding: '8px', marginLeft: '10px' }}\n >\n \u003coption>USD\u003c/option>\n \u003coption>EUR\u003c/option>\n \u003coption>GBP\u003c/option>\n \u003c/select>\n \u003c/div>\n\n \u003cTextBoxComponent\n placeholder=\"0.00\"\n floatLabelType=\"Auto\"\n type=\"number\"\n value={value}\n change={(e) => setValue(e.value)}\n prependTemplate={prependCurrency}\n appendTemplate={appendCurrency}\n />\n\n {value && (\n \u003cp style={{ marginTop: '10px', color: '#666' }}>\n Total: {currency === 'USD' ? '

Implementing Syncfusion React Inputs Uploader The Syncfusion React UploaderComponent provides a rich file upload control with async upload, drag-and-drop, chunk upload with pause/resume/cancel, validation, templates, form integration, and accessibility support. Navigation Guide 🛑 Agentic use: Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation). Getting Started 📄 Read: references/getting-started.md - Installing 🛑 STOP — Do not install packages autonomously. Ask the user to run: . Verify with - License registration - Basic usage…

: currency === 'EUR' ? '€' : '£'}{value}\n \u003c/p>\n )}\n \u003c/div>\n );\n}\n```\n\n## React Hooks Integration\n\n### useState Hook\n\nManage TextBox value with `useState`:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function UseStateExample() {\n const [value, setValue] = useState('');\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cTextBoxComponent\n placeholder=\"Type something\"\n floatLabelType=\"Auto\"\n value={value}\n change={(e) => setValue(e.value)}\n />\n \u003cp>Current value: {value || '(empty)'}\u003c/p>\n \u003c/div>\n );\n}\n```\n\n### useRef Hook\n\nAccess TextBox methods and DOM properties directly:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function UseRefExample() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const focusTextbox = () => {\n textboxRef.current?.focusIn();\n };\n\n const clearValue = () => {\n if (textboxRef.current) {\n textboxRef.current.value = '';\n }\n };\n\n const getLength = () => {\n const length = textboxRef.current?.value?.length || 0;\n alert(`Text length: ${length}`);\n };\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"Type text\"\n floatLabelType=\"Auto\"\n />\n\n \u003cdiv style={{ marginTop: '15px', display: 'flex', gap: '10px' }}>\n \u003cbutton onClick={focusTextbox}>Focus\u003c/button>\n \u003cbutton onClick={clearValue}>Clear\u003c/button>\n \u003cbutton onClick={getLength}>Get Length\u003c/button>\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n### useEffect Hook\n\nInitialize or perform side effects:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useEffect } from 'react';\n\nexport default function UseEffectExample() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n useEffect(() => {\n // Focus TextBox on component mount\n textboxRef.current?.focusIn();\n\n // Set icon after component mounts\n if (textboxRef.current) {\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n }, []); // Empty dependency array: runs once on mount\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"Auto-focused on load\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n### useReducer Hook\n\nManage complex form state:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useReducer } from 'react';\n\ninterface FormState {\n name: string;\n email: string;\n message: string;\n}\n\ntype FormAction = {\n type: 'SET_FIELD';\n field: keyof FormState;\n value: string;\n} | {\n type: 'RESET';\n};\n\nfunction formReducer(state: FormState, action: FormAction): FormState {\n switch (action.type) {\n case 'SET_FIELD':\n return { ...state, [action.field]: action.value };\n case 'RESET':\n return { name: '', email: '', message: '' };\n default:\n return state;\n }\n}\n\nexport default function UseReducerExample() {\n const initialState: FormState = { name: '', email: '', message: '' };\n const [state, dispatch] = useReducer(formReducer, initialState);\n\n const handleChange = (field: keyof FormState, value: string) => {\n dispatch({ type: 'SET_FIELD', field, value });\n };\n\n const handleReset = () => {\n dispatch({ type: 'RESET' });\n };\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003ch2>Contact Form\u003c/h2>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Name\"\n floatLabelType=\"Auto\"\n value={state.name}\n change={(e) => handleChange('name', e.value)}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n type=\"email\"\n value={state.email}\n change={(e) => handleChange('email', e.value)}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Message\"\n floatLabelType=\"Auto\"\n multiline={true}\n value={state.message}\n change={(e) => handleChange('message', e.value)}\n />\n \u003c/div>\n\n \u003cbutton onClick={handleReset}>Reset Form\u003c/button>\n\n \u003cpre style={{ marginTop: '20px', backgroundColor: '#f5f5f5', padding: '10px' }}>\n {JSON.stringify(state, null, 2)}\n \u003c/pre>\n \u003c/div>\n );\n}\n```\n\n## Event Handling\n\n### Change Event\n\nTriggered when the TextBox value changes:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ChangeEventExample() {\n const handleChange = (e: any) => {\n console.log('New value:', e.value);\n console.log('Previous value:', e.previousValue);\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Type to trigger change event\"\n floatLabelType=\"Auto\"\n change={handleChange}\n />\n );\n}\n```\n\n### Created Event\n\nTriggered after the component initializes:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function CreatedEventExample() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreated = () => {\n console.log('TextBox created successfully');\n \n if (textboxRef.current) {\n // Add icon after creation\n textboxRef.current.addIcon('append', 'e-icons e-search');\n \n // Set initial focus\n textboxRef.current.focusIn();\n }\n };\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"TextBox with initialization\"\n floatLabelType=\"Auto\"\n created={handleCreated}\n />\n );\n}\n```\n\n### Input Event\n\nTriggered on every keystroke (real-time):\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function InputEventExample() {\n const [charCount, setCharCount] = useState(0);\n\n const handleInput = (e: any) => {\n setCharCount(e.value.length);\n };\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n placeholder=\"Type to see character count\"\n floatLabelType=\"Auto\"\n input={handleInput}\n />\n \u003cp>Characters: {charCount}\u003c/p>\n \u003c/div>\n );\n}\n```\n\n## Form Integration\n\n### Complete Form with Validation\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { FormValidator } from '@syncfusion/ej2-inputs';\nimport { useEffect, useRef, useState } from 'react';\n\nexport default function CompleteForm() {\n const [formData, setFormData] = useState({\n name: '',\n email: '',\n phone: '',\n message: ''\n });\n\n const formRef = useRef\u003cHTMLFormElement>(null);\n const nameRef = useRef\u003cTextBoxComponent>(null);\n\n useEffect(() => {\n // Initialize form validator\n if (formRef.current) {\n const validator = new FormValidator('#contact-form', {\n rules: {\n name: { required: [true, 'Name is required'] },\n email: { \n required: [true, 'Email is required'],\n email: [true, 'Enter valid email']\n },\n phone: { required: [true, 'Phone is required'] },\n message: { required: [true, 'Message is required'] }\n }\n });\n }\n\n // Auto-focus name field\n nameRef.current?.focusIn();\n }, []);\n\n const handleChange = (field: string, value: string) => {\n setFormData({ ...formData, [field]: value });\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n console.log('Form submitted:', formData);\n alert('Form submitted successfully!');\n };\n\n return (\n \u003cform \n ref={formRef}\n id=\"contact-form\"\n onSubmit={handleSubmit}\n style={{ maxWidth: '500px', margin: '30px auto' }}\n >\n \u003ch2>Contact Us\u003c/h2>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n ref={nameRef}\n name=\"name\"\n placeholder=\"Full Name\"\n floatLabelType=\"Auto\"\n value={formData.name}\n change={(e) => handleChange('name', e.value)}\n data-msg-containerid=\"error-name\"\n />\n \u003cdiv id=\"error-name\">\u003c/div>\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n name=\"email\"\n type=\"email\"\n placeholder=\"Email Address\"\n floatLabelType=\"Auto\"\n value={formData.email}\n change={(e) => handleChange('email', e.value)}\n data-msg-containerid=\"error-email\"\n />\n \u003cdiv id=\"error-email\">\u003c/div>\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n name=\"phone\"\n type=\"tel\"\n placeholder=\"Phone Number\"\n floatLabelType=\"Auto\"\n value={formData.phone}\n change={(e) => handleChange('phone', e.value)}\n data-msg-containerid=\"error-phone\"\n />\n \u003cdiv id=\"error-phone\">\u003c/div>\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n name=\"message\"\n placeholder=\"Your Message\"\n floatLabelType=\"Auto\"\n multiline={true}\n value={formData.message}\n change={(e) => handleChange('message', e.value)}\n data-msg-containerid=\"error-message\"\n />\n \u003cdiv id=\"error-message\">\u003c/div>\n \u003c/div>\n\n \u003cbutton \n type=\"submit\"\n style={{\n width: '100%',\n padding: '12px',\n backgroundColor: '#2196F3',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '16px'\n }}\n >\n Send Message\n \u003c/button>\n \u003c/form>\n );\n}\n```\n\n## See Also\n\n- [Features and Groups](./features-and-groups.md) - Floating labels and icons\n- [Validation and States](./validation-and-states.md) - Input validation\n- [Multiline TextBox](./multiline-textbox.md) - Textarea mode\n- [Getting Started](./getting-started.md) - Basic setup\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":17307,"content_sha256":"652ee717a19a831b159f4577cfa2d3a4e666b913661cd6999e69d13ccef43e1f"},{"filename":"references/textbox-api.md","content":"# Syncfusion React TextBox API Reference\n\nComplete API reference for the `TextBoxComponent` from `@syncfusion/ej2-react-inputs`.\n\n**Import:**\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n```\n\n---\n\n## Properties\n\n### appendTemplate\n\n`string | function | JSX.Element`\n\nSpecifies the HTML template for custom elements to append (right side) to the TextBox input. Supports icons, buttons, or any valid HTML. Updates dynamically on property change. The template function must return `JSX.Element`.\n\n**Default:** `null`\n\n**Function Signature:** `() => JSX.Element`\n\n```tsx\nfunction appendTemplate(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan className=\"e-icons e-eye\">\u003c/span>\n \u003c/>\n );\n}\n\n\u003cTextBoxComponent appendTemplate={appendTemplate} />\n```\n\n---\n\n### autocomplete\n\n`string`\n\nSpecifies whether the browser is allowed to automatically enter or select a value for the textbox.\n\n**Possible values:**\n- `'on'` – Autocomplete is enabled (default)\n- `'off'` – Autocomplete is disabled\n\n**Default:** `'on'`\n\n```tsx\n\u003cTextBoxComponent autocomplete=\"off\" placeholder=\"Enter Name\" />\n```\n\n---\n\n### cssClass\n\n`string`\n\nSpecifies the CSS class value appended to the wrapper of the TextBox. Use this to apply predefined size classes (`e-small`, `e-bigger`), validation states (`e-error`, `e-warning`, `e-success`), or custom appearance classes like `e-corner`.\n\n**Default:** `''`\n\n```tsx\n\u003cTextBoxComponent cssClass=\"e-corner\" placeholder=\"Enter Date\" />\n\u003cTextBoxComponent cssClass=\"e-small\" placeholder=\"Small TextBox\" />\n\u003cTextBoxComponent cssClass=\"e-bigger\" placeholder=\"Large TextBox\" />\n\u003cTextBoxComponent cssClass=\"e-error\" placeholder=\"Error State\" />\n\u003cTextBoxComponent cssClass=\"e-warning\" placeholder=\"Warning State\" />\n\u003cTextBoxComponent cssClass=\"e-success\" placeholder=\"Success State\" />\n```\n\n---\n\n### enablePersistence\n\n`boolean`\n\nEnable or disable persisting TextBox state between page reloads. If enabled, the `value` state will be persisted.\n\n**Default:** `false`\n\n```tsx\n\u003cTextBoxComponent enablePersistence={true} placeholder=\"Persisted Input\" />\n```\n\n---\n\n### enableRtl\n\n`boolean`\n\nEnable or disable rendering the component in right-to-left direction.\n\n**Default:** `false`\n\n```tsx\n\u003cTextBoxComponent enableRtl={true} placeholder=\"RTL TextBox\" />\n```\n\n---\n\n### enabled\n\n`boolean`\n\nSpecifies a Boolean value that indicates whether the TextBox allows user interaction. Set to `false` to disable the TextBox.\n\n**Default:** `true`\n\n```tsx\n\u003cTextBoxComponent enabled={false} placeholder=\"Disabled TextBox\" />\n```\n\n---\n\n### floatLabelType\n\n`FloatLabelType`\n\nSpecifies the floating label behavior of the TextBox — how the placeholder text floats above the TextBox.\n\n**Possible values:**\n- `'Never'` – The placeholder text never floats (default)\n- `'Always'` – The placeholder text always floats above the TextBox\n- `'Auto'` – The placeholder text floats when the TextBox is focused or has a value\n\n**Default:** `'Never'`\n\n```tsx\n\u003cTextBoxComponent placeholder=\"First Name\" floatLabelType=\"Auto\" />\n\u003cTextBoxComponent placeholder=\"Last Name\" floatLabelType=\"Always\" />\n\u003cTextBoxComponent placeholder=\"Email\" floatLabelType=\"Never\" />\n```\n\n---\n\n### htmlAttributes\n\n`{ [key: string]: string }`\n\nYou can add additional HTML attributes such as `disabled`, `value`, `name`, `type`, `maxlength`, etc. to the element. If both property and equivalent HTML attribute are configured, the component considers the property value.\n\n**Default:** `{}`\n\n```tsx\nimport * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nclass App extends React.Component {\n public htmlAttributes = { name: \"username\", type: \"password\", maxlength: \"8\" };\n public render() {\n return (\u003cTextBoxComponent htmlAttributes={this.htmlAttributes} />);\n }\n}\n\nexport default App;\n```\n\n---\n\n### locale\n\n`string`\n\nOverrides the global culture and localization value for this component.\n\n**Default:** `''` (uses global culture `'en-US'`)\n\n```tsx\n\u003cTextBoxComponent locale=\"fr-FR\" placeholder=\"Enter Name\" />\n```\n\n---\n\n### multiline\n\n`boolean`\n\nSpecifies a boolean value that enables or disables multiline mode on the TextBox. The TextBox changes from single-line to multiline (textarea) when this is enabled.\n\n**Default:** `false`\n\n```tsx\n\u003cTextBoxComponent multiline={true} placeholder=\"Enter your address\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### placeholder\n\n`string`\n\nSpecifies the text shown as a hint/placeholder until the user focuses or enters a value. The behavior depends on the `floatLabelType` property.\n\n**Default:** `null`\n\n```tsx\n\u003cTextBoxComponent placeholder=\"Enter your name\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### prependTemplate\n\n`string | function | JSX.Element`\n\nSpecifies the HTML template for custom elements to prepend (left side) to the TextBox input. Supports icons, buttons, or any valid HTML. Updates dynamically on property change. The template function must return `JSX.Element`.\n\n**Default:** `null`\n\n**Function Signature:** `() => JSX.Element`\n\n```tsx\nfunction prependTemplate(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-icons e-user\">\u003c/span>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003c/>\n );\n}\n\n\u003cTextBoxComponent prependTemplate={prependTemplate} placeholder=\"Enter Name\" />\n```\n\n---\n\n### readonly\n\n`boolean`\n\nSpecifies the boolean value whether the TextBox allows users to change the text. When `true`, the input can be read and selected but not edited.\n\n**Default:** `false`\n\n```tsx\n\u003cTextBoxComponent readonly={true} value=\"Read only text\" placeholder=\"Read-only\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### showClearButton\n\n`boolean`\n\nSpecifies a Boolean value that indicates whether the clear button is displayed in the TextBox. The clear button appears only when the input has a value.\n\n**Default:** `false`\n\n```tsx\n\u003cTextBoxComponent showClearButton={true} placeholder=\"Enter text\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### type\n\n`string`\n\nSpecifies the behavior of the TextBox such as `text`, `password`, `email`, `number`, `tel`, etc.\n\n**Default:** `'text'`\n\n```tsx\n\u003cTextBoxComponent type=\"password\" placeholder=\"Enter password\" floatLabelType=\"Auto\" />\n\u003cTextBoxComponent type=\"email\" placeholder=\"Enter email\" floatLabelType=\"Auto\" />\n\u003cTextBoxComponent type=\"number\" placeholder=\"Enter number\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### value\n\n`string`\n\nSets the content of the TextBox.\n\n**Default:** `null`\n\n```tsx\n\u003cTextBoxComponent value=\"Initial value\" placeholder=\"Enter Name\" floatLabelType=\"Auto\" />\n```\n\n---\n\n### width\n\n`number | string`\n\nSpecifies the width of the TextBox component.\n\n**Default:** `null`\n\n```tsx\n\u003cTextBoxComponent width=\"300px\" placeholder=\"Enter Name\" />\n\u003cTextBoxComponent width={400} placeholder=\"Enter Name\" />\n```\n\n---\n\n## Methods\n\n### addAttributes\n\nAdding multiple attributes as key-value pairs to the TextBox element.\n\n**Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `attributes` | `{ [key: string]: string }` | Specifies the attributes to add to the TextBox element. |\n\n**Returns:** `void`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addAttributes({ maxlength: '150', rows: '3' });\n }\n };\n\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}\n```\n\n---\n\n### addIcon\n\nAdding icons to the TextBox component. Creates a `\u003cspan>` element with the given icon class(es) placed at the specified position.\n\n**Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `position` | `string` | Icon placement — `'append'` (right) or `'prepend'` (left). |\n| `icons` | `string \\| string[]` | Icon CSS class(es) to apply to the created span element. |\n\n**Returns:** `void`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addIcon('prepend', 'e-icons e-user');\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Date\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}\n```\n\n---\n\n### destroy\n\nRemoves the component from the DOM and detaches all its related event handlers. Also maintains the initial TextBox element from the DOM.\n\n**Returns:** `void`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleDestroy = () => {\n textboxRef.current?.destroy();\n };\n\n return (\n \u003c>\n \u003cTextBoxComponent ref={textboxRef} placeholder=\"Enter text\" />\n \u003cbutton onClick={handleDestroy}>Destroy\u003c/button>\n \u003c/>\n );\n}\n```\n\n---\n\n### focusIn\n\nSets the focus to the TextBox widget for interaction.\n\n**Returns:** `void`\n\n```tsx\nimport { useRef, useEffect } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n useEffect(() => {\n textboxRef.current?.focusIn();\n }, []);\n\n return (\n \u003cTextBoxComponent ref={textboxRef} placeholder=\"Auto-focused\" floatLabelType=\"Auto\" />\n );\n}\n```\n\n---\n\n### focusOut\n\nRemoves the focus from the TextBox widget if it is in a focused state.\n\n**Returns:** `void`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleBlur = () => {\n textboxRef.current?.focusOut();\n };\n\n return (\n \u003c>\n \u003cTextBoxComponent ref={textboxRef} placeholder=\"Enter text\" />\n \u003cbutton onClick={handleBlur}>Remove Focus\u003c/button>\n \u003c/>\n );\n}\n```\n\n---\n\n### getPersistData\n\nGets the properties to be maintained in the persisted state.\n\n**Returns:** `string`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const logPersistData = () => {\n const data = textboxRef.current?.getPersistData();\n console.log('Persist data:', data);\n };\n\n return (\n \u003c>\n \u003cTextBoxComponent ref={textboxRef} placeholder=\"Enter text\" enablePersistence={true} />\n \u003cbutton onClick={logPersistData}>Get Persist Data\u003c/button>\n \u003c/>\n );\n}\n```\n\n---\n\n### removeAttributes\n\nRemoving multiple attributes by name from the TextBox element.\n\n**Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `attributes` | `string[]` | Specifies the attribute names to remove from the TextBox element. |\n\n**Returns:** `void`\n\n```tsx\nimport { useRef } from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addAttributes({ maxlength: '10', readonly: 'true' });\n }\n };\n\n const handleRemove = () => {\n if (textboxRef.current) {\n textboxRef.current.removeAttributes(['maxlength', 'readonly']);\n }\n };\n\n return (\n \u003c>\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n created={handleCreate}\n />\n \u003cbutton onClick={handleRemove}>Remove Attributes\u003c/button>\n \u003c/>\n );\n}\n```\n\n---\n\n## Events\n\n### blur\n\n`EmitType\u003cFocusOutEventArgs>`\n\nTriggers when the TextBox loses focus (focus-out).\n\n**Event Arguments (`FocusOutEventArgs`):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `event` | `MouseEvent \\| TouchEvent` | Specifies the original event arguments. |\n| `value` | `string` | Returns the current value of the TextBox. |\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const handleBlur = (args: any) => {\n console.log('TextBox blurred, value:', args.value);\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n blur={handleBlur}\n />\n );\n}\n```\n\n---\n\n### change\n\n`EmitType\u003cChangedEventArgs>`\n\nTriggers when the content of the TextBox has changed and gets focus-out.\n\n**Event Arguments (`ChangedEventArgs`):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `event` | `Event` | Specifies the original event arguments. |\n| `value` | `string` | Returns the current value of the TextBox. |\n| `previousValue` | `string` | Returns the previous value of the TextBox. |\n| `isInteraction` | `boolean` | Returns `true` if the change was triggered by a user interaction. |\n| `isInteracted` | `boolean` | Returns `true` if the TextBox component was interacted by the user. |\n| `container` | `HTMLElement` | Specifies the container element. |\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const handleChange = (args: any) => {\n console.log('New value:', args.value);\n console.log('Previous value:', args.previousValue);\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n change={handleChange}\n />\n );\n}\n```\n\n---\n\n### created\n\n`EmitType\u003cObject>`\n\nTriggers when the TextBox component is created.\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreated = () => {\n console.log('TextBox created');\n if (textboxRef.current) {\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n placeholder=\"Enter Date\"\n floatLabelType=\"Auto\"\n created={handleCreated}\n />\n );\n}\n```\n\n---\n\n### destroyed\n\n`EmitType\u003cObject>`\n\nTriggers when the TextBox component is destroyed.\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const handleDestroyed = () => {\n console.log('TextBox destroyed');\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n destroyed={handleDestroyed}\n />\n );\n}\n```\n\n---\n\n### focus\n\n`EmitType\u003cFocusInEventArgs>`\n\nTriggers when the TextBox gets focus.\n\n**Event Arguments (`FocusInEventArgs`):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `event` | `MouseEvent \\| TouchEvent` | Specifies the original event arguments. |\n| `value` | `string` | Returns the current value of the TextBox. |\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n const handleFocus = (args: any) => {\n console.log('TextBox focused, value:', args.value);\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n focus={handleFocus}\n />\n );\n}\n```\n\n---\n\n### input\n\n`EmitType\u003cInputEventArgs>`\n\nTriggers each time when the value of the TextBox has changed (on every keystroke).\n\n**Event Arguments (`InputEventArgs`):**\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `event` | `Event` | Specifies the original event arguments. |\n| `value` | `string` | Returns the current value of the TextBox. |\n| `previousValue` | `string` | Returns the previous value of the TextBox. |\n| `isInteraction` | `boolean` | Returns `true` if the change was triggered by a user interaction. |\n| `isInteracted` | `boolean` | Returns `true` if the TextBox was interacted by the user. |\n| `container` | `HTMLElement` | Specifies the container element. |\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function App() {\n const [charCount, setCharCount] = useState(0);\n\n const handleInput = (args: any) => {\n setCharCount(args.value.length);\n };\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n placeholder=\"Type something...\"\n floatLabelType=\"Auto\"\n input={handleInput}\n />\n \u003cp>Characters: {charCount}\u003c/p>\n \u003c/div>\n );\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":16613,"content_sha256":"fdaf26b9797f5097860ce80942f7775e33ce52ccb849b9fae98c9679ed408122"},{"filename":"references/textbox-features-and-groups.md","content":"# TextBox Features and Groups\n\n## Table of Contents\n\n- [Floating Labels](#floating-labels)\n- [Icons and Adornments](#icons-and-adornments)\n- [Clear Button](#clear-button)\n- [Rounded Corner](#rounded-corner)\n- [Disabled State](#disabled-state)\n- [Groups](#groups)\n- [Combining Features](#combining-features)\n\n## Floating Labels\n\nFloating labels enhance user experience by automatically animating placeholder text into a label position when the input is focused or has a value.\n\n### Float Label Types\n\n#### Auto (Recommended Default)\n\nThe label floats above the input only when focused or contains a value:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent \n placeholder=\"First Name\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n**Behavior:**\n- **Empty & unfocused:** Placeholder text appears inside the input\n- **Focused or has value:** Placeholder animates above as floating label\n\n#### Always\n\nThe label is always visible above the input, even when empty:\n\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Last Name\"\n floatLabelType=\"Always\"\n/>\n```\n\n**Use when:** You want the label always visible for clarity\n\n#### Never\n\nNo floating label behavior; placeholder remains inside the input:\n\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Never\"\n/>\n```\n\n**Use when:** Space is limited or you prefer traditional placeholder-only design\n\n### Complete Float Label Example\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function FloatLabelDemo() {\n const [values, setValues] = useState({\n firstName: '',\n lastName: '',\n email: ''\n });\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>FloatLabelType: Auto\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"First Name\"\n floatLabelType=\"Auto\"\n value={values.firstName}\n change={(e) => setValues({ ...values, firstName: e.value })}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>FloatLabelType: Always\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Last Name\"\n floatLabelType=\"Always\"\n value={values.lastName}\n change={(e) => setValues({ ...values, lastName: e.value })}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>FloatLabelType: Never\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Never\"\n type=\"email\"\n value={values.email}\n change={(e) => setValues({ ...values, email: e.value })}\n />\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n## Icons and Adornments\n\nAdd visual context or interactive elements using icons. Icons can be placed before (prepend) or after (append) the input.\n\n### Using addIcon Method\n\nThe `addIcon()` method adds icons to the TextBox during the `created` event:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function IconExample() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n // addIcon(position, iconClass)\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Date\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}\n```\n\n### Icon Positions\n\n#### Append (Right Side)\n\n```tsx\ntextboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n```\n\nResult:\n```\n┌──────────────────────────┐\n│ Enter Date 📅 │\n└──────────────────────────┘\n```\n\n#### Prepend (Left Side)\n\n```tsx\ntextboxRef.current.addIcon('prepend', 'e-icons e-user');\n```\n\nResult:\n```\n┌──────────────────────────┐\n│ 👤 Enter Name │\n└──────────────────────────┘\n```\n\n#### Both Sides\n\n```tsx\nconst handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addIcon('prepend', 'e-icons e-user');\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n};\n```\n\nResult:\n```\n┌──────────────────────────────┐\n│ 👤 Enter Date 📅 │\n└──────────────────────────────┘\n```\n\n### Common Icon Classes\n\n| Icon Class | Visual | Use Case |\n|-----------|--------|----------|\n| `e-input-popup-date` | 📅 Calendar | Date/date-time inputs |\n| `e-input-down` | ⬇️ Dropdown arrow | Dropdown/combo inputs |\n| `e-user` | 👤 User profile | Username/name fields |\n| `e-people` | 👥 Group | Team/group fields |\n| `e-trash` | 🗑️ Delete | Clear/remove action |\n| `e-eye` | 👁️ Eye open | Show password toggle |\n| `e-eye-slash` | 👁️‍🗨️ Eye closed | Hide password toggle |\n\n## Clear Button\n\nThe clear button automatically appears when the input has a value and disappears when empty, providing users a quick way to reset the field.\n\n### Enabling Clear Button\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ClearButtonExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter your text\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n />\n );\n}\n```\n\n**Behavior:**\n- **Empty:** No clear button visible\n- **Has value:** Clear button (×) appears on the right\n- **Click clear button:** Input value clears, button disappears\n\n### Clear Button with Icons\n\nCombine clear button with prepended icons:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function ClearWithIcon() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addIcon('prepend', 'e-icons e-user');\n }\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter username\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}\n```\n\nResult:\n```\nEmpty:\n┌────────────────────────────┐\n│ 👤 Enter username │\n└────────────────────────────┘\n\nWith value:\n┌────────────────────────────┐\n│ 👤 john_doe × │\n└────────────────────────────┘\n```\n\n### Custom Clear Button Action\n\nMonitor when clear button is clicked:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function ClearWithAction() {\n const [inputValue, setInputValue] = useState('');\n\n const handleChange = (e: any) => {\n setInputValue(e.value);\n };\n\n return (\n \u003c>\n \u003cTextBoxComponent\n placeholder=\"Search...\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={inputValue}\n change={handleChange}\n />\n \u003cp>Current value: {inputValue || '(empty)'}\u003c/p>\n \u003c/>\n );\n}\n```\n\n## Rounded Corner\n\nApply rounded corners to the TextBox by adding the `e-corner` CSS class using the `cssClass` property. This creates a modern, polished appearance.\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function RoundedCornerExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Date\"\n cssClass=\"e-corner\"\n />\n );\n}\n```\n\n## Disabled State\n\nDisable user interaction with the TextBox by setting the `enabled` property to `false`. A disabled TextBox prevents input, prevents focus, and displays with reduced opacity.\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function DisabledExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Name\"\n enabled={false}\n />\n );\n}\n```\n\n### Toggle Enabled/Disabled State\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function ToggleEnabled() {\n const [isEnabled, setIsEnabled] = useState(true);\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n enabled={isEnabled}\n />\n \u003cbutton onClick={() => setIsEnabled(!isEnabled)}>\n {isEnabled ? 'Disable' : 'Enable'} TextBox\n \u003c/button>\n \u003c/div>\n );\n}\n```\n\n## Groups\n\nGroups organize related input elements together with optional labels, icons, and styling.\n\n### Icon with Floating Label\n\nCombine icons and floating labels for enhanced input groups:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function IconWithFloatingLabel() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cdiv>\n \u003ch4>TextBox with icon and floating label\u003c/h4>\n \u003cTextBoxComponent\n id=\"date-input\"\n placeholder=\"Enter Date\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n />\n \u003c/div>\n );\n}\n```\n\n### Multiple Inputs with Clear Buttons\n\nCreate a group of related inputs, each with clear button:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function SearchFilters() {\n const [filters, setFilters] = useState({\n name: '',\n email: '',\n phone: ''\n });\n\n const handleChange = (field: string, value: string) => {\n setFilters({ ...filters, [field]: value });\n };\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003ch3>Search Filters\u003c/h3>\n\n \u003cdiv style={{ marginBottom: '15px' }}>\n \u003cTextBoxComponent\n placeholder=\"Name\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={filters.name}\n change={(e) => handleChange('name', e.value)}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '15px' }}>\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n type=\"email\"\n value={filters.email}\n change={(e) => handleChange('email', e.value)}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '15px' }}>\n \u003cTextBoxComponent\n placeholder=\"Phone\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={filters.phone}\n change={(e) => handleChange('phone', e.value)}\n />\n \u003c/div>\n\n \u003cbutton>Search\u003c/button>\n \u003c/div>\n );\n}\n```\n\n## Combining Features\n\n### Comprehensive Example: Complete Registration Form\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState, useRef } from 'react';\n\nexport default function RegistrationForm() {\n const [formData, setFormData] = useState({\n firstName: '',\n lastName: '',\n email: '',\n password: '',\n phone: '',\n address: ''\n });\n\n const passwordRef = useRef\u003cTextBoxComponent>(null);\n\n const handleChange = (field: string, value: string) => {\n setFormData({ ...formData, [field]: value });\n };\n\n const togglePasswordVisibility = () => {\n if (passwordRef.current) {\n const currentType = passwordRef.current.type;\n passwordRef.current.type = currentType === 'password' ? 'text' : 'password';\n }\n };\n\n const handleCreate = () => {\n if (passwordRef.current) {\n passwordRef.current.addIcon('append', 'e-icons e-eye');\n }\n };\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto', padding: '20px' }}>\n \u003ch2>User Registration\u003c/h2>\n\n {/* First Name */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"First Name\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={formData.firstName}\n change={(e) => handleChange('firstName', e.value)}\n />\n \u003c/div>\n\n {/* Last Name */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Last Name\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={formData.lastName}\n change={(e) => handleChange('lastName', e.value)}\n />\n \u003c/div>\n\n {/* Email */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Email Address\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n type=\"email\"\n value={formData.email}\n change={(e) => handleChange('email', e.value)}\n />\n \u003c/div>\n\n {/* Password with visibility toggle */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n ref={passwordRef}\n type=\"password\"\n placeholder=\"Password\"\n floatLabelType=\"Auto\"\n value={formData.password}\n change={(e) => handleChange('password', e.value)}\n created={handleCreate}\n />\n \u003c/div>\n\n {/* Phone */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Phone Number\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n type=\"tel\"\n value={formData.phone}\n change={(e) => handleChange('phone', e.value)}\n />\n \u003c/div>\n\n {/* Address (multiline) */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Address\"\n floatLabelType=\"Auto\"\n multiline={true}\n value={formData.address}\n change={(e) => handleChange('address', e.value)}\n />\n \u003c/div>\n\n \u003cbutton style={{ padding: '10px 20px' }}>Submit\u003c/button>\n \u003c/div>\n );\n}\n```\n\nThis example demonstrates:\n- ✅ Floating labels for all inputs\n- ✅ Clear button on most fields\n- ✅ Icons with password visibility toggle\n- ✅ Different input types (email, tel, password)\n- ✅ Multiline input for address\n- ✅ State management with `useState`\n\n## See Also\n\n- [Getting Started](./getting-started.md) - Initial setup and installation\n- [Styling and Sizing](./styling-and-sizing.md) - Size variations and CSS customization\n- [Validation and States](./validation-and-states.md) - Error, warning, and success states\n- [Advanced Features](./advanced-features.md) - Adornments and React hooks\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14902,"content_sha256":"b88f1e925fdc03525e483c14efd6d7fb5a5d901fd1930bcf834c19b8dabcab85"},{"filename":"references/textbox-getting-started.md","content":"# Getting Started with React TextBox Component\n\n## Table of Contents\n\n- [Project Setup](#project-setup)\n- [Installing TextBox Package](#installing-textbox-package)\n- [Adding CSS References](#adding-css-references)\n- [Creating Your First TextBox](#creating-your-first-textbox)\n- [Adding Icons to TextBox](#adding-icons-to-textbox)\n- [Running the Application](#running-the-application)\n- [Floating Labels](#floating-labels)\n\n## Project Setup\n\n### Using Vite (Recommended)\n\nVite provides a faster development environment with smaller bundle sizes compared to create-react-app. Create a new React application:\n\n```bash\nnpm create vite@latest my-textbox-app\n```\n\nWhen prompted, select:\n- **Framework:** React\n- **Variant:** JavaScript or TypeScript (as needed)\n\n```bash\ncd my-textbox-app\nnpm run dev\n```\n\n### Using Create React App\n\nIf you prefer create-react-app:\n\n```bash\nnpx create-react-app my-textbox-app\ncd my-textbox-app\nnpm start\n```\n\n## Installing TextBox Package\n\nInstall the Syncfusion React inputs package (which includes TextBox):\n\n```bash\nnpm install @syncfusion/ej2-react-inputs --save\n```\n\nThe `--save` flag adds the package to your `package.json` dependencies.\n\n> **Note:** Make sure you have Node.js 14+ installed. Check with `node --version`.\n\n## Adding CSS References\n\n### Step 1: Import CSS in App.css\n\nAdd the following CSS imports to your `src/App.css` file:\n\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/textbox/index.css\";\n```\n\nThese imports provide:\n- **ej2-base:** Core Syncfusion styles\n- **ej2-icons:** Icon library used for adornments\n- **ej2-react-inputs:** TextBox-specific styling\n\n### Alternative Themes\n\nSyncfusion provides multiple theme options. Replace `tailwind3.css` with one of:\n\n- `bootstrap5.css` - Bootstrap 5 theme\n- `material.css` - Material Design theme\n- `fluent.css` - Microsoft Fluent theme\n- `highcontrast.css` - High contrast for accessibility\n\n```css\n/* Example: Using Material theme */\n@import \"../node_modules/@syncfusion/ej2-base/styles/material.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/material.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/material.css\";\n```\n\n### Step 2: Import CSS in App.tsx\n\nEnsure `App.css` is imported in your main `App.tsx`:\n\n```tsx\nimport './App.css';\n```\n\n## Creating Your First TextBox\n\n### Basic TextBox (Class Component)\n\n```tsx\nimport * as React from \"react\";\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport './App.css';\n\nexport default class App extends React.Component\u003c{}, {}> {\n public render() {\n return (\n \u003cTextBoxComponent \n id=\"textbox-default\"\n placeholder=\"Enter Name\"\n />\n );\n }\n}\n```\n\n### Basic TextBox (Functional Component)\n\n```tsx\nimport React from \"react\";\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport './App.css';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent \n id=\"textbox-default\"\n placeholder=\"Enter Name\"\n />\n );\n}\n```\n\n### Output\n\nThe TextBox renders as a styled input field with a placeholder:\n\n```\n┌─────────────────────────┐\n│ Enter Name │\n└─────────────────────────┘\n```\n\n## Adding Icons to TextBox\n\n### Adding a Single Icon\n\nAdd an icon after the input using the `addIcon()` method and the `created` event:\n\n**Functional Component:**\n\n```tsx\nimport React, { useRef } from \"react\";\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport './App.css';\n\nexport default function App() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n // addIcon(position, iconClass)\n // position: 'append' (right) or 'prepend' (left)\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cTextBoxComponent\n id=\"textbox-icon\"\n placeholder=\"Enter Date\"\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}\n```\n\n### Available Icon Classes\n\nSyncfusion provides icon classes with the format `e-icons e-{icon-name}`:\n\n- `e-input-popup-date` - Calendar icon\n- `e-input-down` - Dropdown arrow\n- `e-user` - User/profile icon\n- `e-people` - Group/people icon\n- `e-trash` - Delete/trash icon\n- `e-eye` - Eye icon (visibility)\n- `e-eye-slash` - Eye with slash icon\n\n### Adding Multiple Icons\n\nAdd icons on both sides:\n\n```tsx\nconst handleCreate = () => {\n if (textboxRef.current) {\n // Icon on the left (prepend)\n textboxRef.current.addIcon('prepend', 'e-icons e-user');\n // Icon on the right (append)\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n};\n```\n\n### Output\n\n```\n┌──────────────────────────────┐\n│ 👤 Enter Date 📅 │\n└──────────────────────────────┘\n```\n\n### Custom Icon Styling\n\nAdd CSS to style icons:\n\n```css\n.e-input-group .e-icons.e-input-popup-date {\n font-size: 16px;\n color: #007bff;\n}\n```\n\n## Running the Application\n\n### Vite Development Server\n\n```bash\nnpm run dev\n```\n\nOutput:\n```\n Local: http://localhost:5173/\n press h to show help\n```\n\nOpen `http://localhost:5173/` in your browser to see the TextBox.\n\n### Create React App Development Server\n\n```bash\nnpm start\n```\n\nThe browser opens automatically, showing your TextBox component.\n\n## Floating Labels\n\nThe floating label feature automatically animates the placeholder text above the input when focused or filled.\n\n### Floating Label Types\n\n#### Auto (Recommended)\n\nLabel floats when input is focused or has a value:\n\n```tsx\n\u003cTextBoxComponent \n placeholder=\"First Name\"\n floatLabelType=\"Auto\"\n/>\n```\n\nBehavior:\n- Empty and unfocused: Placeholder shows inside input\n- Focused or has value: Placeholder moves above input as label\n\n#### Always\n\nLabel always floats above the input:\n\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Last Name\"\n floatLabelType=\"Always\"\n/>\n```\n\nBehavior: Label is always visible above, even when empty and unfocused\n\n#### Never (Default)\n\nPlaceholder stays inside the input (no floating label):\n\n```tsx\n\u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Never\"\n/>\n```\n\n### Complete Floating Label Example\n\n```tsx\nimport React from \"react\";\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport './App.css';\n\nexport default function App() {\n return (\n \u003cdiv>\n \u003ch3>Floating Label Examples\u003c/h3>\n \n \u003cdiv>\n \u003clabel>Auto - Float on focus/fill\u003c/label>\n \u003cTextBoxComponent \n placeholder=\"First Name\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n \u003cdiv>\n \u003clabel>Always - Label always visible\u003c/label>\n \u003cTextBoxComponent \n placeholder=\"Last Name\"\n floatLabelType=\"Always\"\n />\n \u003c/div>\n\n \u003cdiv>\n \u003clabel>Never - Placeholder inside input\u003c/label>\n \u003cTextBoxComponent \n placeholder=\"Email\"\n floatLabelType=\"Never\"\n />\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n## Next Steps\n\n- **Add validation:** See [Validation and States](./validation-and-states.md) for error/warning/success states\n- **Customize styling:** See [Styling and Sizing](./styling-and-sizing.md) for size and appearance options\n- **Add clear button:** See [Features and Groups](./features-and-groups.md) for built-in functionality\n- **Use multiline:** See [Multiline TextBox](./multiline-textbox.md) for textarea mode\n- **Advanced features:** See [Advanced Features](./advanced-features.md) for adornments and hooks\n\n## Troubleshooting\n\n**Issue:** Styles not applied (no borders or spacing)\n\n**Solution:** Ensure CSS imports are in `App.css`:\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css\";\n```\n\n**Issue:** Icons not showing\n\n**Solution:** Icons require `ej2-icons` CSS import. Add to `App.css`:\n```css\n@import \"../node_modules/@syncfusion/ej2-icons/styles/tailwind3.css\";\n```\n\n**Issue:** TextBox not rendering\n\n**Solution:** \n1. Verify package is installed: `npm list @syncfusion/ej2-react-inputs`\n2. Check import path: `from '@syncfusion/ej2-react-inputs'`\n3. Verify `App.css` imports are correct\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8427,"content_sha256":"1ebd4a39ae3230dca46ee2f26afea9b3f530977e2af0c7e80d974ac7f1048a1a"},{"filename":"references/textbox-multiline-textbox.md","content":"# Multiline TextBox\n\n## Table of Contents\n\n- [Creating Multiline TextBox](#creating-multiline-textbox)\n- [Floating Labels with Multiline](#floating-labels-with-multiline)\n- [Auto-Resizing TextBox](#auto-resizing-textbox)\n- [Disabling Resize](#disabling-resize)\n- [Limiting Text Length](#limiting-text-length)\n- [Character Counting](#character-counting)\n\n## Creating Multiline TextBox\n\nTransform the TextBox component into a multiline input (textarea) for capturing longer text content like addresses, comments, descriptions, or messages.\n\n### Basic Multiline\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineExample() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n />\n );\n}\n```\n\n**Default Behavior:**\n- Renders as an HTML `\u003ctextarea>` element\n- Users can manually resize the textarea by dragging the bottom-right corner\n- No floating label by default\n\n### Multiline with Value\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineWithValue() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n value=\"123 Main Street, Suite 100, New York, NY 10001\"\n />\n );\n}\n```\n\n## Floating Labels with Multiline\n\nCombine floating labels with multiline input for better UX:\n\n### Floating Label Types\n\n#### Auto (Recommended)\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineFloatingAuto() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n**Behavior:** Label floats above when focused or has content\n\n#### Always\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineFloatingAlways() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Always\"\n />\n );\n}\n```\n\n**Behavior:** Label always visible above textarea\n\n#### Never\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineFloatingNever() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Never\"\n />\n );\n}\n```\n\n### Complete Example: All Float Types\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MultilineFloatingDemo() {\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '30px' }}>\n \u003clabel>\u003cstrong>Float Label Type: Auto\u003c/strong>\u003c/label>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '30px' }}>\n \u003clabel>\u003cstrong>Float Label Type: Always\u003c/strong>\u003c/label>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Always\"\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '30px' }}>\n \u003clabel>\u003cstrong>Float Label Type: Never\u003c/strong>\u003c/label>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Never\"\n />\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n## Auto-Resizing TextBox\n\nCreate a multiline TextBox that automatically expands vertically as users type more content. This provides a seamless typing experience without manual resizing.\n\n### Implementation with Functional Component\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function AutoResizeTextbox() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n // Set initial height based on scroll height\n const element = textboxRef.current.respectiveElement as HTMLTextAreaElement;\n element.style.height = 'auto';\n element.style.height = element.scrollHeight + 'px';\n }\n };\n\n const handleInput = () => {\n if (textboxRef.current) {\n // Update height as user types\n const element = textboxRef.current.respectiveElement as HTMLTextAreaElement;\n element.style.height = 'auto';\n element.style.height = element.scrollHeight + 'px';\n }\n };\n\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Start typing and the box will expand automatically...\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n input={handleInput}\n style={{ minHeight: '60px', resize: 'none' }}\n />\n );\n}\n```\n\n### Implementation with Class Component\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nexport default class AutoResizeTextbox extends React.Component {\n private textboxRef = React.createRef\u003cTextBoxComponent>();\n\n private handleCreate = () => {\n const element = (this.textboxRef.current?.respectiveElement) as HTMLTextAreaElement;\n if (element) {\n element.style.height = 'auto';\n element.style.height = element.scrollHeight + 'px';\n }\n };\n\n private handleInput = () => {\n const element = (this.textboxRef.current?.respectiveElement) as HTMLTextAreaElement;\n if (element) {\n element.style.height = 'auto';\n element.style.height = element.scrollHeight + 'px';\n }\n };\n\n public render() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Start typing...\"\n floatLabelType=\"Auto\"\n ref={this.textboxRef}\n created={this.handleCreate}\n input={this.handleInput}\n style={{ minHeight: '60px', resize: 'none' }}\n />\n );\n }\n}\n```\n\n### CSS for Auto-Resize\n\n```css\n.auto-resize-textbox textarea,\n.e-float-input textarea {\n resize: none;\n overflow: hidden;\n min-height: 60px;\n padding: 12px;\n font-size: 15px;\n line-height: 1.5;\n transition: height 0.2s ease;\n}\n```\n\n## Disabling Resize\n\nBy default, multiline TextBox allows users to manually resize. Disable this behavior with CSS:\n\n### CSS to Disable Resize\n\n```css\ntextarea.e-input,\n.e-float-input textarea,\n.e-float-input.e-control-wrapper textarea,\n.e-input-group textarea,\n.e-input-group.e-control-wrapper textarea {\n resize: none;\n}\n```\n\n### Disable in Component\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function NoResizeTextbox() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"This textarea cannot be resized\"\n floatLabelType=\"Auto\"\n cssClass=\"disable-resize\"\n />\n );\n}\n```\n\n**App.css:**\n\n```css\n.disable-resize {\n resize: none;\n}\n\n.disable-resize textarea,\n.disable-resize.e-float-input textarea {\n resize: none !important;\n}\n```\n\n## Limiting Text Length\n\nControl the maximum number of characters users can enter using the `maxLength` property:\n\n### Using maxLength via htmlAttributes\n\nPass `maxlength` as an HTML attribute using the `htmlAttributes` property:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function MaxLengthTextbox() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Maximum 200 characters\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ maxlength: '200' }}\n />\n );\n}\n```\n\n### Adding maxLength Programmatically\n\nUse the `addAttributes` method to add maxLength after component creation:\n\n**Functional Component:**\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function ProgrammaticMaxLength() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n\n const addMaxLength = () => {\n if (textboxRef.current) {\n textboxRef.current.addAttributes({ maxlength: 150 });\n }\n };\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Click button to add max length limit\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n />\n \u003cbutton onClick={addMaxLength} style={{ marginTop: '10px' }}>\n Add Max Length (150 chars)\n \u003c/button>\n \u003c/div>\n );\n}\n```\n\n**Class Component:**\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nexport default class ProgrammaticMaxLength extends React.Component {\n private textboxRef = React.createRef\u003cTextBoxComponent>();\n\n private addMaxLength = () => {\n if (this.textboxRef.current) {\n this.textboxRef.current.addAttributes({ maxlength: 150 });\n }\n };\n\n public render() {\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Click to add max length\"\n floatLabelType=\"Auto\"\n ref={this.textboxRef}\n />\n \u003cbutton onClick={this.addMaxLength}>Add Max Length\u003c/button>\n \u003c/div>\n );\n }\n}\n```\n\n## Character Counting\n\nDisplay a live character count as users type:\n\n### Simple Character Counter\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function CharacterCounter() {\n const [count, setCount] = useState(0);\n const maxChars = 200;\n\n const handleInput = (e: any) => {\n setCount(e.value.length);\n };\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Type your message...\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ maxlength: maxChars.toString() }}\n input={handleInput}\n />\n \u003cdiv style={{ marginTop: '8px', fontSize: '14px', color: '#666' }}>\n {count} / {maxChars} characters\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n### Advanced Counter with Warning\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function AdvancedCharacterCounter() {\n const [count, setCount] = useState(0);\n const [text, setText] = useState('');\n const maxChars = 300;\n const warningThreshold = 250;\n\n const handleInput = (e: any) => {\n const value = e.value;\n setText(value);\n setCount(value.length);\n };\n\n const percentUsed = (count / maxChars) * 100;\n const isWarning = count > warningThreshold;\n const isFull = count === maxChars;\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Type your feedback...\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ maxlength: maxChars.toString() }}\n value={text}\n input={handleInput}\n cssClass={isFull ? 'e-error' : isWarning ? 'e-warning' : ''}\n />\n\n \u003cdiv style={{ marginTop: '12px' }}>\n {/* Character Count Display */}\n \u003cdiv style={{ \n fontSize: '14px',\n color: isFull ? '#F44336' : isWarning ? '#FF9800' : '#666',\n fontWeight: 'bold'\n }}>\n {count} / {maxChars} characters\n {isWarning && count \u003c maxChars && (\n \u003cspan style={{ marginLeft: '10px', color: '#FF9800' }}>\n ⚠️ Approaching limit\n \u003c/span>\n )}\n {isFull && (\n \u003cspan style={{ marginLeft: '10px', color: '#F44336' }}>\n ❌ Maximum reached\n \u003c/span>\n )}\n \u003c/div>\n\n {/* Progress Bar */}\n \u003cdiv style={{\n marginTop: '8px',\n height: '6px',\n backgroundColor: '#E0E0E0',\n borderRadius: '3px',\n overflow: 'hidden'\n }}>\n \u003cdiv style={{\n height: '100%',\n width: `${percentUsed}%`,\n backgroundColor: isFull ? '#F44336' : isWarning ? '#FF9800' : '#4CAF50',\n transition: 'all 0.3s ease'\n }} />\n \u003c/div>\n \u003c/div>\n\n {/* Word Count (Bonus) */}\n \u003cdiv style={{ marginTop: '10px', fontSize: '13px', color: '#999' }}>\n Words: {text.trim().split(/\\s+/).filter(w => w.length > 0).length}\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n### Counter with Class Component\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nexport default class CharacterCounter extends React.Component\u003c{}, { count: number }> {\n constructor(props: {}) {\n super(props);\n this.state = { count: 0 };\n }\n\n private maxChars = 300;\n\n private handleInput = (e: any) => {\n this.setState({ count: e.value.length });\n };\n\n public render() {\n const { count } = this.state;\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Type your comment...\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ maxlength: this.maxChars.toString() }}\n input={this.handleInput}\n />\n \u003cdiv style={{ marginTop: '8px', fontSize: '14px', color: '#666' }}>\n {count} / {this.maxChars} characters\n \u003c/div>\n \u003c/div>\n );\n }\n}\n```\n\n## Complete Example: Feedback Form\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState, useRef } from 'react';\n\nexport default function FeedbackForm() {\n const [feedback, setFeedback] = useState('');\n const [charCount, setCharCount] = useState(0);\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n const maxChars = 500;\n\n const handleFeedbackChange = (e: any) => {\n setFeedback(e.value);\n setCharCount(e.value.length);\n };\n\n const handleAutoResize = () => {\n if (textboxRef.current) {\n const element = textboxRef.current.respectiveElement as HTMLTextAreaElement;\n element.style.height = 'auto';\n element.style.height = element.scrollHeight + 'px';\n }\n };\n\n const handleCreate = () => {\n handleAutoResize();\n };\n\n const handleSubmit = () => {\n if (feedback.trim().length === 0) {\n alert('Please enter your feedback');\n return;\n }\n console.log('Feedback submitted:', feedback);\n alert('Thank you for your feedback!');\n setFeedback('');\n setCharCount(0);\n };\n\n return (\n \u003cdiv style={{ maxWidth: '600px', margin: '30px auto', padding: '20px' }}>\n \u003ch2>Send Us Your Feedback\u003c/h2>\n \u003cp>We value your feedback and would love to hear from you.\u003c/p>\n\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Please share your thoughts, suggestions, or concerns...\"\n floatLabelType=\"Auto\"\n htmlAttributes={{ maxlength: maxChars.toString() }}\n value={feedback}\n input={handleFeedbackChange}\n created={handleCreate}\n ref={textboxRef}\n style={{ minHeight: '150px', resize: 'none' }}\n />\n\n {/* Character Counter */}\n \u003cdiv style={{ \n marginTop: '12px', \n fontSize: '14px',\n color: charCount > maxChars * 0.9 ? '#FF9800' : '#666'\n }}>\n \u003cstrong>{charCount}\u003c/strong> / {maxChars} characters\n {charCount > maxChars * 0.9 && (\n \u003cspan style={{ marginLeft: '10px', color: '#FF9800' }}>\n ⚠️ Approaching limit\n \u003c/span>\n )}\n \u003c/div>\n\n {/* Submit Button */}\n \u003cbutton \n onClick={handleSubmit}\n style={{\n marginTop: '20px',\n padding: '12px 24px',\n backgroundColor: '#2196F3',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '16px'\n }}\n >\n Submit Feedback\n \u003c/button>\n \u003c/div>\n );\n}\n```\n\n## See Also\n\n- [Getting Started](./getting-started.md) - Basic TextBox setup\n- [Features and Groups](./features-and-groups.md) - Floating labels and icons\n- [Styling and Sizing](./styling-and-sizing.md) - CSS customization\n- [Advanced Features](./advanced-features.md) - React hooks and adornments\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15890,"content_sha256":"9c88a508e4bdefedbb1ed5d312b149b092940e4fc175c9b263ec6d8ec24ec170"},{"filename":"references/textbox-styling-and-sizing.md","content":"# Styling and Sizing\n\n## Table of Contents\n\n- [Predefined Sizes](#predefined-sizes)\n- [Rounded Corner](#rounded-corner)\n- [CSS Customization](#css-customization)\n- [Floating Label Styling](#floating-label-styling)\n- [TextBox Wrapper Styling](#textbox-wrapper-styling)\n- [Theme Variations](#theme-variations)\n\n## Predefined Sizes\n\nThe TextBox component supports three predefined sizes to match different layout requirements:\n\n| Size | CSS Class | Use Case |\n|------|-----------|----------|\n| **Normal** | (default) | Standard desktop layouts |\n| **Small** | `e-small` | Compact forms, limited space, dense UIs |\n| **Large** | `e-bigger` | Mobile interfaces, touch targets, better accessibility |\n\n### Applying Size Classes\n\nUse the `cssClass` property to apply size classes:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function SizeExample() {\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n {/* Normal Size (Default) */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Normal Size\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n {/* Small Size */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Small Size\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n cssClass=\"e-small\"\n />\n \u003c/div>\n\n {/* Large Size */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Large Size\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Enter text\"\n floatLabelType=\"Auto\"\n cssClass=\"e-bigger\"\n />\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n### Size Comparison\n\n```\nNormal: ┌─────────────────────┐\n │ Enter text │\n └─────────────────────┘ (height: ~38px)\n\nSmall: ┌──────────────┐\n │ Enter text │\n └──────────────┘ (height: ~30px)\n\nLarge: ┌─────────────────────────┐\n │ Enter text │\n └─────────────────────────┘ (height: ~48px)\n```\n\n### Combining Size with Other Classes\n\nApply multiple classes using string concatenation:\n\n```tsx\n\u003cTextBoxComponent\n placeholder=\"Search\"\n floatLabelType=\"Auto\"\n cssClass=\"e-small\"\n/>\n```\n\n## Rounded Corner\n\nApply rounded corners to the TextBox by adding the `e-corner` CSS class using the `cssClass` property. This creates a modern, polished appearance that aligns with contemporary design standards.\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function RoundedCornerExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Date\"\n cssClass=\"e-corner\"\n />\n );\n}\n```\n\nYou can also combine `e-corner` with size classes:\n\n```tsx\n\u003cTextBoxComponent placeholder=\"Small rounded\" cssClass=\"e-corner e-small\" floatLabelType=\"Auto\" />\n\u003cTextBoxComponent placeholder=\"Large rounded\" cssClass=\"e-corner e-bigger\" floatLabelType=\"Auto\" />\n```\n\n## CSS Customization\n\nCustomize TextBox appearance with CSS rules targeting various selectors.\n\n### Custom Font Size and Height\n\n```css\n/* Apply to all TextBox inputs */\n.e-input:not(:valid),\n.e-input:valid,\n.e-float-input.e-control-wrapper input:not(:valid),\n.e-float-input.e-control-wrapper input:valid,\n.e-float-input input:not(:valid),\n.e-float-input input:valid,\n.e-input-group input:not(:valid),\n.e-input-group input:valid,\n.e-input-group.e-control-wrapper input:not(:valid),\n.e-input-group.e-control-wrapper input:valid,\n.e-float-input.e-control-wrapper textarea:not(:valid),\n.e-float-input.e-control-wrapper textarea:valid,\n.e-float-input textarea:not(:valid),\n.e-float-input textarea:valid,\n.e-input-group.e-control-wrapper textarea:not(:valid),\n.e-input-group.e-control-wrapper textarea:valid,\n.e-input-group textarea:not(:valid),\n.e-input-group textarea:valid {\n font-size: 16px;\n height: 45px;\n padding: 10px 12px;\n}\n```\n\n**In App.tsx:**\n\n```tsx\nimport './App.css';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Custom sized input\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n### Custom Border and Colors\n\n```css\n.e-input:focus,\n.e-float-input input:focus,\n.e-input-group input:focus {\n border-color: #2196F3;\n box-shadow: 0 0 5px rgba(33, 150, 243, 0.3);\n}\n\n.e-input {\n border: 2px solid #E0E0E0;\n border-radius: 4px;\n}\n```\n\n### Custom Background Color\n\n```css\n.e-float-input.e-control-wrapper,\n.e-input-group {\n background-color: #F5F5F5;\n border-radius: 8px;\n}\n\n.e-float-input.e-control-wrapper input,\n.e-input-group input {\n background-color: #F5F5F5;\n}\n\n.e-input:focus {\n background-color: #FFFFFF;\n}\n```\n\n### Custom Padding and Spacing\n\n```css\n.e-input,\n.e-float-input input {\n padding: 12px 16px;\n}\n\n/* Increase spacing for better touch targets */\n.e-bigger .e-input,\n.e-bigger .e-float-input input {\n padding: 14px 18px;\n}\n```\n\n## Floating Label Styling\n\nCustomize the appearance of floating labels with CSS:\n\n### Floating Label Color\n\n```css\n/* Floating label color and font size */\n.e-float-input.e-control-wrapper:not(.e-error) input:valid ~ label.e-float-text,\n.e-float-input.e-control-wrapper:not(.e-error) input ~ label.e-label-top.e-float-text {\n color: #2196F3;\n font-size: 14px;\n font-weight: 500;\n}\n```\n\n### Custom Floating Label Animation\n\n```css\n/* Smooth floating label transition */\n.e-float-text {\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* Floating label in focused state */\n.e-input-focus ~ .e-float-text,\n.e-input:valid ~ .e-float-text {\n font-size: 12px;\n color: #1976D2;\n transform: translateY(-1.5em);\n}\n```\n\n### Floating Label Color by State\n\n```css\n/* Success state - green floating label */\n.e-success input:valid ~ label.e-float-text {\n color: #4CAF50;\n}\n\n/* Error state - red floating label */\n.e-error input ~ label.e-float-text {\n color: #F44336;\n}\n\n/* Warning state - orange floating label */\n.e-warning input ~ label.e-float-text {\n color: #FF9800;\n}\n```\n\n### Complete Floating Label Example\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport './App.css';\n\nexport default function StyledFloatingLabel() {\n const [formData, setFormData] = useState({\n username: '',\n email: '',\n password: ''\n });\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '40px auto' }}>\n \u003ch2>User Registration\u003c/h2>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Username\"\n floatLabelType=\"Auto\"\n value={formData.username}\n change={(e) => setFormData({ ...formData, username: e.value })}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n type=\"email\"\n value={formData.email}\n change={(e) => setFormData({ ...formData, email: e.value })}\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Password\"\n floatLabelType=\"Auto\"\n type=\"password\"\n value={formData.password}\n change={(e) => setFormData({ ...formData, password: e.value })}\n />\n \u003c/div>\n\n \u003cbutton style={{ width: '100%', padding: '12px' }}>Register\u003c/button>\n \u003c/div>\n );\n}\n```\n\n**CSS in App.css:**\n\n```css\n/* Custom floating label styling */\n.e-float-input.e-control-wrapper:not(.e-error) input:valid ~ label.e-float-text,\n.e-float-input.e-control-wrapper:not(.e-error) input ~ label.e-label-top.e-float-text {\n color: #2196F3;\n font-size: 14px;\n font-weight: 600;\n}\n\n/* Custom input styling */\n.e-input {\n border: 2px solid #E0E0E0;\n border-radius: 6px;\n padding: 12px 14px;\n font-size: 15px;\n transition: all 0.3s ease;\n}\n\n.e-input:focus {\n border-color: #2196F3;\n box-shadow: 0 0 8px rgba(33, 150, 243, 0.2);\n background-color: #F8FBFF;\n}\n\nbutton {\n background-color: #2196F3;\n color: white;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 16px;\n transition: background-color 0.3s ease;\n}\n\nbutton:hover {\n background-color: #1976D2;\n}\n```\n\n## TextBox Wrapper Styling\n\nStyle the container element that wraps the TextBox:\n\n### Add Margin and Spacing\n\n```css\n.e-float-input,\n.e-input-group {\n margin-bottom: 20px;\n}\n```\n\n### Create Cards/Containers\n\n```css\n.textbox-container {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 24px;\n background-color: #FFFFFF;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.textbox-container .e-float-input {\n margin-bottom: 0;\n}\n```\n\n**Usage:**\n\n```tsx\n\u003cdiv className=\"textbox-container\">\n \u003cTextBoxComponent placeholder=\"Name\" floatLabelType=\"Auto\" />\n \u003cTextBoxComponent placeholder=\"Email\" floatLabelType=\"Auto\" />\n \u003cTextBoxComponent placeholder=\"Phone\" floatLabelType=\"Auto\" />\n\u003c/div>\n```\n\n### Responsive Layout\n\n```css\n@media (max-width: 768px) {\n .e-input {\n font-size: 16px; /* Prevents mobile zoom */\n padding: 14px 16px;\n }\n\n .e-bigger {\n padding: 16px 18px;\n }\n}\n```\n\n## Theme Variations\n\nSyncfusion provides multiple built-in themes. Switch themes by changing CSS imports in `App.css`:\n\n### Available Themes\n\n#### Material Design (Default)\n\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/material.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/material.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/material.css\";\n```\n\n#### Bootstrap 5\n\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/bootstrap5.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/bootstrap5.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/bootstrap5.css\";\n```\n\n#### Fluent (Microsoft Design)\n\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/fluent.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/fluent.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/fluent.css\";\n```\n\n#### High Contrast (Accessibility)\n\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/highcontrast.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/highcontrast.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/highcontrast.css\";\n```\n\n#### Tailwind 3 (Recommended)\n\n```css\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-icons/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css\";\n```\n\n### Theme Switching at Runtime\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport './App.css';\n\nexport default function ThemeSwitcher() {\n const [theme, setTheme] = useState('material');\n\n const switchTheme = (selectedTheme: string) => {\n setTheme(selectedTheme);\n document.documentElement.setAttribute('data-theme', selectedTheme);\n };\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cbutton onClick={() => switchTheme('material')}>Material\u003c/button>\n \u003cbutton onClick={() => switchTheme('bootstrap5')}>Bootstrap 5\u003c/button>\n \u003cbutton onClick={() => switchTheme('fluent')}>Fluent\u003c/button>\n \u003c/div>\n\n \u003cTextBoxComponent\n placeholder=\"Try different themes\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n );\n}\n```\n\n## Complete Styling Example\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\nimport './App.css';\n\nexport default function StyledFormApp() {\n const [formData, setFormData] = useState({\n name: '',\n email: '',\n message: ''\n });\n\n const handleChange = (field: string, value: string) => {\n setFormData({ ...formData, [field]: value });\n };\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '40px auto', padding: '20px' }}>\n \u003ch2>Contact Form\u003c/h2>\n\n \u003cdiv className=\"form-group\">\n \u003cTextBoxComponent\n placeholder=\"Full Name\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n value={formData.name}\n change={(e) => handleChange('name', e.value)}\n />\n \u003c/div>\n\n \u003cdiv className=\"form-group\">\n \u003cTextBoxComponent\n placeholder=\"Email Address\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n type=\"email\"\n value={formData.email}\n change={(e) => handleChange('email', e.value)}\n />\n \u003c/div>\n\n \u003cdiv className=\"form-group\">\n \u003cTextBoxComponent\n placeholder=\"Message\"\n floatLabelType=\"Auto\"\n multiline={true}\n value={formData.message}\n change={(e) => handleChange('message', e.value)}\n />\n \u003c/div>\n\n \u003cbutton className=\"submit-btn\">Send Message\u003c/button>\n \u003c/div>\n );\n}\n```\n\n**App.css:**\n\n```css\n.form-group {\n margin-bottom: 20px;\n}\n\n.e-input,\n.e-float-input input {\n border: 2px solid #E0E0E0;\n border-radius: 6px;\n padding: 12px 14px;\n font-size: 15px;\n transition: all 0.3s ease;\n}\n\n.e-input:focus,\n.e-float-input input:focus {\n border-color: #2196F3;\n box-shadow: 0 0 8px rgba(33, 150, 243, 0.2);\n}\n\n.e-float-input.e-control-wrapper:not(.e-error) input ~ label.e-float-text {\n color: #2196F3;\n font-weight: 600;\n}\n\n.submit-btn {\n width: 100%;\n padding: 12px 20px;\n background-color: #2196F3;\n color: white;\n border: none;\n border-radius: 6px;\n font-size: 16px;\n cursor: pointer;\n transition: background-color 0.3s ease;\n}\n\n.submit-btn:hover {\n background-color: #1976D2;\n}\n```\n\n## See Also\n\n- [Getting Started](./getting-started.md) - CSS imports and theme setup\n- [Features and Groups](./features-and-groups.md) - Floating labels and icons\n- [Validation and States](./validation-and-states.md) - Error/warning/success styling\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14089,"content_sha256":"11d4bcf1bec47dae5820e10684f1c6f3439bd4c100dfee539127a708f18210d4"},{"filename":"references/textbox-validation-and-states.md","content":"# Validation and States\n\n## Table of Contents\n\n- [Validation States](#validation-states)\n- [Disabled State](#disabled-state)\n- [Read-Only State](#read-only-state)\n- [Dynamic State Changes](#dynamic-state-changes)\n- [Color Changes Based on Value](#color-changes-based-on-value)\n\n## Validation States\n\nThe TextBox supports three predefined validation states to provide visual feedback: `error`, `warning`, and `success`. Apply these states using CSS classes via the `cssClass` property.\n\n### Error State\n\nUse the error state to indicate invalid input:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ErrorStateExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Input with error\"\n cssClass=\"e-error\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n**Appearance:**\n- Red border around the input\n- Red floating label (if applicable)\n- Typically used for invalid email, required fields not filled, etc.\n\n### Warning State\n\nUse the warning state to highlight caution or potential issues:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function WarningStateExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Input with warning\"\n cssClass=\"e-warning\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n**Appearance:**\n- Orange/yellow border\n- Orange/yellow floating label\n- Used for weak passwords, future dates, etc.\n\n### Success State\n\nUse the success state to indicate valid input:\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function SuccessStateExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Input with success\"\n cssClass=\"e-success\"\n floatLabelType=\"Auto\"\n />\n );\n}\n```\n\n**Appearance:**\n- Green border\n- Green floating label\n- Used for confirmed entries, validated data, etc.\n\n### All Three States\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ValidationStatesDemo() {\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Warning State\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Input with warning\"\n cssClass=\"e-warning\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Error State\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Input with error\"\n cssClass=\"e-error\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Success State\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Input with success\"\n cssClass=\"e-success\"\n floatLabelType=\"Auto\"\n />\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n### Functional Component with Validation\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function ValidatedInput() {\n const [email, setEmail] = useState('');\n const [validationState, setValidationState] = useState('');\n\n const validateEmail = (value: string) => {\n if (!value) {\n setValidationState(''); // No state when empty\n } else if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {\n setValidationState('e-success');\n } else {\n setValidationState('e-error');\n }\n };\n\n const handleChange = (e: any) => {\n const value = e.value;\n setEmail(value);\n validateEmail(value);\n };\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003ch3>Email Validation\u003c/h3>\n \u003cTextBoxComponent\n type=\"email\"\n placeholder=\"Enter email\"\n floatLabelType=\"Auto\"\n value={email}\n change={handleChange}\n cssClass={validationState}\n />\n \u003cp style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>\n {validationState === 'e-success' && '✓ Valid email'}\n {validationState === 'e-error' && '✗ Invalid email format'}\n {!validationState && 'Enter an email address'}\n \u003c/p>\n \u003c/div>\n );\n}\n```\n\n### Class Component with Validation\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nexport default class ValidatedInput extends React.Component\u003c{}, { \n password: string;\n validationState: string;\n}> {\n constructor(props: {}) {\n super(props);\n this.state = { password: '', validationState: '' };\n }\n\n private validatePassword = (value: string) => {\n if (!value) {\n this.setState({ validationState: '' });\n } else if (value.length \u003c 8) {\n this.setState({ validationState: 'e-warning' });\n } else if (value.length >= 12) {\n this.setState({ validationState: 'e-success' });\n } else {\n this.setState({ validationState: 'e-warning' });\n }\n };\n\n private handleChange = (e: any) => {\n const value = e.value;\n this.setState({ password: value });\n this.validatePassword(value);\n };\n\n public render() {\n const { password, validationState } = this.state;\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003ch3>Password Strength\u003c/h3>\n \u003cTextBoxComponent\n type=\"password\"\n placeholder=\"Enter password\"\n floatLabelType=\"Auto\"\n value={password}\n change={this.handleChange}\n cssClass={validationState}\n />\n \u003cp style={{ marginTop: '10px', fontSize: '14px' }}>\n {validationState === 'e-warning' && '⚠️ Weak password (min 8 characters)'}\n {validationState === 'e-success' && '✓ Strong password'}\n {!validationState && 'Enter at least 8 characters'}\n \u003c/p>\n \u003c/div>\n );\n }\n}\n```\n\n## Disabled State\n\nDisable TextBox to prevent user interaction while keeping it visible. Use the `enabled` property set to `false`:\n\n### Basic Disabled State\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function DisabledExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"This input is disabled\"\n floatLabelType=\"Auto\"\n enabled={false}\n value=\"Cannot edit this value\"\n />\n );\n}\n```\n\n**Behavior:**\n- Input appears greyed out\n- User cannot click or type\n- Value cannot be changed\n\n### Toggle Enabled/Disabled State\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function ToggleDisabled() {\n const [isEnabled, setIsEnabled] = useState(true);\n const [inputValue, setInputValue] = useState('Type here');\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cbutton onClick={() => setIsEnabled(!isEnabled)}>\n {isEnabled ? 'Disable' : 'Enable'} Input\n \u003c/button>\n \u003c/div>\n\n \u003cTextBoxComponent\n placeholder=\"Try to edit\"\n floatLabelType=\"Auto\"\n enabled={isEnabled}\n value={inputValue}\n change={(e) => setInputValue(e.value)}\n />\n\n \u003cp style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>\n State: {isEnabled ? '🔓 Enabled' : '🔒 Disabled'}\n \u003c/p>\n \u003c/div>\n );\n}\n```\n\n## Read-Only State\n\nMake the input read-only so users can view and select the content but cannot edit it. Use the `readonly` property:\n\n### Basic Read-Only State\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function ReadOnlyExample() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Read-only value\"\n floatLabelType=\"Auto\"\n readonly={true}\n value=\"This value cannot be edited\"\n />\n );\n}\n```\n\n**Behavior:**\n- Input appears normal (not greyed out)\n- User can select and copy the text\n- User cannot edit the content\n- Can be focused and included in tab order\n\n### Disabled (`enabled={false}`) vs Read-Only (`readonly={true}`)\n\n| Feature | Disabled (`enabled={false}`) | Read-Only (`readonly={true}`) |\n|---------|------------------------------|-------------------------------|\n| **Appearance** | Greyed out | Normal |\n| **Selectable** | No | Yes |\n| **Copyable** | No | Yes |\n| **Tab Focus** | No | Yes |\n| **Form Submit** | Excluded | Included |\n| **Use Case** | Temporary disable | Display data, prevent editing |\n\n### Example: Disabled vs Read-Only\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function DisabledVsReadOnly() {\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '20px auto' }}>\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Disabled State (enabled=false)\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Disabled\"\n floatLabelType=\"Auto\"\n enabled={false}\n value=\"Cannot select or edit\"\n />\n \u003csmall>Greyed out, not copyable\u003c/small>\n \u003c/div>\n\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003ch4>Read-Only State\u003c/h4>\n \u003cTextBoxComponent\n placeholder=\"Read-Only\"\n floatLabelType=\"Auto\"\n readonly={true}\n value=\"Can select and copy but not edit\"\n />\n \u003csmall>Normal appearance, selectable\u003c/small>\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n## Dynamic State Changes\n\nChange validation states dynamically based on user input or application logic:\n\n### Form Validation Example\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function FormValidation() {\n const [formData, setFormData] = useState({\n username: '',\n email: '',\n password: ''\n });\n\n const [validationStates, setValidationStates] = useState({\n username: '',\n email: '',\n password: ''\n });\n\n // Username validation: min 3 characters\n const validateUsername = (value: string) => {\n if (!value) return '';\n return value.length \u003c 3 ? 'e-error' : 'e-success';\n };\n\n // Email validation\n const validateEmail = (value: string) => {\n if (!value) return '';\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value) ? 'e-success' : 'e-error';\n };\n\n // Password validation: min 8 characters, mix of letter and number\n const validatePassword = (value: string) => {\n if (!value) return '';\n const hasLetters = /[a-zA-Z]/.test(value);\n const hasNumbers = /[0-9]/.test(value);\n \n if (value.length \u003c 8) return 'e-error';\n if (!hasLetters || !hasNumbers) return 'e-warning';\n return 'e-success';\n };\n\n const handleUsernameChange = (e: any) => {\n const value = e.value;\n setFormData({ ...formData, username: value });\n setValidationStates({\n ...validationStates,\n username: validateUsername(value)\n });\n };\n\n const handleEmailChange = (e: any) => {\n const value = e.value;\n setFormData({ ...formData, email: value });\n setValidationStates({\n ...validationStates,\n email: validateEmail(value)\n });\n };\n\n const handlePasswordChange = (e: any) => {\n const value = e.value;\n setFormData({ ...formData, password: value });\n setValidationStates({\n ...validationStates,\n password: validatePassword(value)\n });\n };\n\n const isFormValid = \n validationStates.username === 'e-success' &&\n validationStates.email === 'e-success' &&\n validationStates.password === 'e-success';\n\n return (\n \u003cdiv style={{ maxWidth: '500px', margin: '30px auto' }}>\n \u003ch2>Create Account\u003c/h2>\n\n {/* Username */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Username\"\n floatLabelType=\"Auto\"\n value={formData.username}\n change={handleUsernameChange}\n cssClass={validationStates.username}\n />\n \u003csmall style={{ display: 'block', marginTop: '5px', color: '#666' }}>\n {validationStates.username === 'e-success' && '✓ Valid username'}\n {validationStates.username === 'e-error' && '✗ At least 3 characters required'}\n \u003c/small>\n \u003c/div>\n\n {/* Email */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Email\"\n floatLabelType=\"Auto\"\n type=\"email\"\n value={formData.email}\n change={handleEmailChange}\n cssClass={validationStates.email}\n />\n \u003csmall style={{ display: 'block', marginTop: '5px', color: '#666' }}>\n {validationStates.email === 'e-success' && '✓ Valid email'}\n {validationStates.email === 'e-error' && '✗ Invalid email format'}\n \u003c/small>\n \u003c/div>\n\n {/* Password */}\n \u003cdiv style={{ marginBottom: '20px' }}>\n \u003cTextBoxComponent\n placeholder=\"Password\"\n floatLabelType=\"Auto\"\n type=\"password\"\n value={formData.password}\n change={handlePasswordChange}\n cssClass={validationStates.password}\n />\n \u003csmall style={{ display: 'block', marginTop: '5px', color: '#666' }}>\n {validationStates.password === 'e-success' && '✓ Strong password'}\n {validationStates.password === 'e-warning' && '⚠️ Include letters and numbers'}\n {validationStates.password === 'e-error' && '✗ At least 8 characters required'}\n \u003c/small>\n \u003c/div>\n\n {/* Submit Button */}\n \u003cbutton \n disabled={!isFormValid}\n style={{\n padding: '12px 20px',\n backgroundColor: isFormValid ? '#4CAF50' : '#CCC',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: isFormValid ? 'pointer' : 'not-allowed'\n }}\n >\n Create Account\n \u003c/button>\n\n \u003cp style={{ marginTop: '15px', fontSize: '14px', color: '#666' }}>\n Form Status: {isFormValid ? '✓ All fields valid' : '✗ Complete the form'}\n \u003c/p>\n \u003c/div>\n );\n}\n```\n\n## Color Changes Based on Value\n\nChange TextBox colors dynamically based on input using the `input` event (fires on every keystroke) or `change` event (fires on blur):\n\n### Dynamic Color Example\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function DynamicColorTextbox() {\n const [cssClass, setCssClass] = useState('');\n\n const handleInput = (e: any) => {\n const inputValue = e.value;\n\n // Change color based on whether value is numeric\n const isNumeric = /^[0-9]+$/.test(inputValue);\n if (!inputValue) {\n setCssClass('');\n } else if (!isNumeric) {\n setCssClass('e-error');\n } else {\n setCssClass('e-success');\n }\n };\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003ch3>Enter Numeric Values\u003c/h3>\n \u003cTextBoxComponent\n placeholder=\"Enter numeric values\"\n floatLabelType=\"Auto\"\n input={handleInput}\n cssClass={cssClass}\n />\n \u003c/div>\n );\n}\n```\n\n### Stock Price Color Indicator\n\n```tsx\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function StockPriceIndicator() {\n const [price, setPrice] = useState('');\n const [status, setStatus] = useState('');\n const basePrice = 100;\n\n const handleChange = (e: any) => {\n const value = parseFloat(e.value);\n setPrice(e.value);\n\n if (!e.value) {\n setStatus('');\n } else if (isNaN(value)) {\n setStatus('e-error');\n } else {\n const change = value - basePrice;\n if (change > 0) {\n setStatus('e-success'); // Price up - green\n } else if (change \u003c 0) {\n setStatus('e-error'); // Price down - red\n } else {\n setStatus(''); // Price unchanged - normal\n }\n }\n };\n\n const change = parseFloat(price) - basePrice || 0;\n\n return (\n \u003cdiv style={{ maxWidth: '400px', margin: '20px auto' }}>\n \u003ch3>Stock Price Tracker\u003c/h3>\n \u003cp>Base Price: ${basePrice}\u003c/p>\n\n \u003cTextBoxComponent\n placeholder=\"Enter current price\"\n floatLabelType=\"Auto\"\n type=\"number\"\n value={price}\n change={handleChange}\n cssClass={status}\n />\n\n {price && (\n \u003cdiv style={{ marginTop: '10px', fontSize: '14px' }}>\n \u003cp>Change: ${change > 0 ? '+' : ''}{change.toFixed(2)}\u003c/p>\n \u003cp style={{\n color: change > 0 ? '#4CAF50' : change \u003c 0 ? '#F44336' : '#666'\n }}>\n {change > 0 ? '↑ Up' : change \u003c 0 ? '↓ Down' : '→ Unchanged'}\n \u003c/p>\n \u003c/div>\n )}\n \u003c/div>\n );\n}\n```\n\n## See Also\n\n- [Getting Started](./getting-started.md) - Basic setup\n- [Features and Groups](./features-and-groups.md) - Floating labels and icons\n- [Styling and Sizing](./styling-and-sizing.md) - CSS customization\n- [Advanced Features](./advanced-features.md) - React hooks and adornments\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":16700,"content_sha256":"4b349ce0454adcc7ebb88ae77f5213de50290e587954d122218323d318fdf47e"},{"filename":"references/uploader-advanced-how-to.md","content":"# Advanced How-To Scenarios – Syncfusion React Uploader\n\n## Table of Contents\n- [Programmatic File Upload](#programmatic-file-upload)\n- [Invisible / Background Upload](#invisible--background-upload)\n- [Image Preview Before Uploading](#image-preview-before-uploading)\n- [Resize Images Before Upload](#resize-images-before-upload)\n- [Sort Selected Files](#sort-selected-files)\n- [Check File Size Before Upload](#check-file-size-before-upload)\n- [Check MIME Type Before Upload](#check-mime-type-before-upload)\n- [Confirm Dialog Before File Removal](#confirm-dialog-before-file-removal)\n- [Open and Edit Uploaded Files](#open-and-edit-uploaded-files)\n- [Trigger File Browser from External Button](#trigger-file-browser-from-external-button)\n- [Convert Uploaded Image to Binary (Server-Side)](#convert-uploaded-image-to-binary-server-side)\n- [JWT Authentication](#jwt-authentication)\n- [Form Support](#form-support)\n- [Localization](#localization)\n- [Accessibility](#accessibility)\n\n---\n\n## Programmatic File Upload\n\nUpload files without user interaction using the `upload` method. Retrieve queued files with `getFilesData()`.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const uploadAll = (): void => {\n // Upload all queued files\n uploaderRef.current?.upload(uploaderRef.current.getFilesData());\n };\n\n const uploadSpecific = (): void => {\n const files = uploaderRef.current?.getFilesData();\n if (files && files.length > 0) {\n // Upload only the first file\n uploaderRef.current?.upload([files[0]]);\n }\n };\n\n return (\n \u003cdiv>\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n autoUpload={false}\n />\n \u003cbutton onClick={uploadAll}>Upload All\u003c/button>\n \u003cbutton onClick={uploadSpecific}>Upload First File\u003c/button>\n \u003c/div>\n );\n}\n```\n\n- `upload()` with no argument uploads all queued files.\n- `upload(filesData)` uploads only the specified files.\n- `getFilesData(index?)` returns current file list; optional `index` returns a specific item.\n\n---\n\n## Invisible / Background Upload\n\nTrigger an invisible upload (no visible file list) by setting `showFileList={false}` and calling `upload()` in the `selected` event.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n // Upload immediately without showing any UI\n uploaderRef.current?.upload(args.filesData, true);\n args.cancel = true; // Prevent default file list rendering\n };\n\n const onSuccess = (args: any): void => {\n if (args.operation === 'upload') {\n alert(`${args.file.name} uploaded successfully!`);\n }\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n showFileList={false}\n selected={onSelected}\n success={onSuccess}\n />\n );\n}\n```\n\n---\n\n## Image Preview Before Uploading\n\nDisplay image previews using the `selected` event by reading files with `FileReader`.\n\n```tsx\nimport React, { useRef, useState } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const [previews, setPreviews] = useState\u003cstring[]>([]);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n args.filesData.forEach((fileData: any) => {\n const reader = new FileReader();\n reader.onload = (e: any) => {\n setPreviews(prev => [...prev, e.target.result]);\n };\n reader.readAsDataURL(fileData.rawFile);\n });\n };\n\n return (\n \u003cdiv>\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n allowedExtensions=\".jpg,.jpeg,.png,.gif\"\n selected={onSelected}\n />\n \u003cdiv style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>\n {previews.map((src, i) => (\n \u003cimg key={i} src={src} style={{ width: 100, height: 100, objectFit: 'cover' }} alt=\"preview\" />\n ))}\n \u003c/div>\n \u003c/div>\n );\n}\n```\n\n> For a more complete implementation, see the [Syncfusion Image Preview Demo](https://ej2.syncfusion.com/react/demos/#/material/uploader/image-preview).\n\n---\n\n## Resize Images Before Upload\n\nResize images client-side before uploading to reduce server storage and upload time.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nconst MAX_WIDTH = 1000;\nconst MAX_HEIGHT = 600;\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n args.cancel = true; // Prevent default upload\n const fileData = args.filesData[0];\n const reader = new FileReader();\n\n reader.onload = (e: any) => {\n const img = new Image();\n img.onload = () => {\n let { width, height } = img;\n\n if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; }\n if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; }\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n canvas.getContext('2d')!.drawImage(img, 0, 0, width, height);\n\n canvas.toBlob((blob) => {\n if (!blob) return;\n const resizedFile = {\n name: fileData.name,\n rawFile: blob,\n size: blob.size,\n type: fileData.type,\n validationMessage: '',\n statusCode: '1',\n status: 'Ready to Upload'\n };\n // Upload the resized image with custom UI flag\n uploaderRef.current?.upload(resizedFile as any, true);\n }, 'image/png');\n };\n img.src = e.target.result;\n };\n reader.readAsDataURL(fileData.rawFile);\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n allowedExtensions=\".jpg,.jpeg,.png\"\n selected={onSelected}\n />\n );\n}\n```\n\n---\n\n## Sort Selected Files\n\nSort files in the upload queue using the `selected` event and the built-in `sortFileList` method, or custom sort logic.\n\n```tsx\nconst onSelected = (args: any): void => {\n // Sort alphabetically by file name\n args.modifiedFilesData = args.filesData.sort((a: any, b: any) =>\n a.name.localeCompare(b.name)\n );\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} selected={onSelected} />\n```\n\n**Using `sortFileList` method:**\n\n```tsx\nconst onSelected = (args: any): void => {\n // Sort using the built-in method (alphabetically by name)\n const sorted = uploaderRef.current?.sortFileList(args.filesData as any);\n args.modifiedFilesData = sorted as any;\n};\n```\n\n---\n\n## Check File Size Before Upload\n\nInspect file size in the `uploading` event before the upload starts. Use `bytesToSize` for human-readable display.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onUploading = (args: any): void => {\n const sizeStr = uploaderRef.current?.bytesToSize(args.fileData.size);\n console.log(`Uploading: ${args.fileData.name} — Size: ${sizeStr}`);\n\n // Block files larger than 2 MB\n if (args.fileData.size > 2 * 1024 * 1024) {\n args.cancel = true;\n alert(`File \"${args.fileData.name}\" (${sizeStr}) exceeds the 2 MB limit.`);\n }\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n uploading={onUploading}\n />\n );\n}\n```\n\n---\n\n## Check MIME Type Before Upload\n\nRetrieve the MIME type from `args.fileData.rawFile.type` in the `uploading` event.\n\n```tsx\nconst onUploading = (args: any): void => {\n const mimeType = args.fileData.rawFile.type;\n console.log('MIME type:', mimeType);\n\n // Only allow PDF files\n if (mimeType !== 'application/pdf') {\n args.cancel = true;\n alert(`Invalid file type: ${mimeType}. Only PDFs are allowed.`);\n }\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} uploading={onUploading} />\n```\n\n---\n\n## Confirm Dialog Before File Removal\n\nShow a confirmation dialog before removing a file from the server. Use `beforeRemove` to intercept removal.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onBeforeRemove = (args: any): void => {\n // Cancel the default removal\n args.cancel = true;\n\n // Show confirmation dialog\n const confirmed = window.confirm(`Remove \"${args.filesData[0].name}\" from the server?`);\n if (confirmed) {\n // Proceed with removal programmatically\n args.cancel = false;\n }\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n beforeRemove={onBeforeRemove}\n />\n );\n}\n```\n\n> For a richer dialog, integrate the Syncfusion Dialog component (`@syncfusion/ej2-react-popups`) instead of `window.confirm`.\n\n---\n\n## Open and Edit Uploaded Files\n\nAfter a successful upload, retrieve the server file path and attach a click handler to open/edit the file.\n\n```tsx\nconst onSuccess = (args: any): void => {\n if (args.operation !== 'upload') return;\n\n // Server returns file path in response status text\n const filePath = args.e.target.statusText;\n\n // Find the rendered list item for this file\n const liElements = document.querySelectorAll('.e-upload-file-list');\n liElements.forEach((li: Element) => {\n if (li.getAttribute('data-file-name') === args.file.name) {\n li.setAttribute('file-path', filePath);\n li.addEventListener('click', () => {\n const savedPath = li.getAttribute('file-path');\n if (savedPath) {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', '/api/upload/openFile');\n xhr.setRequestHeader('filePath', savedPath);\n xhr.send();\n }\n });\n }\n });\n};\n```\n\n---\n\n## Trigger File Browser from External Button\n\nOpen the file browser from any external button by clicking the hidden file input via the Uploader's browse button.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const triggerBrowse = (): void => {\n const browseBtn = document.querySelector('.e-file-select-wrap button') as HTMLElement;\n browseBtn?.click();\n };\n\n return (\n \u003cdiv>\n \u003cbutton onClick={triggerBrowse}>📎 Attach Files\u003c/button>\n \u003cUploaderComponent asyncSettings={asyncSettings} />\n \u003c/div>\n );\n}\n```\n\n---\n\n## Convert Uploaded Image to Binary (Server-Side)\n\nRead the uploaded file as binary bytes on the server using `BinaryReader`. Client-side upload is standard.\n\n```csharp\n[AcceptVerbs(\"Post\")]\npublic void Save()\n{\n try\n {\n if (System.Web.HttpContext.Current.Request.Files.AllKeys.Length > 0)\n {\n var httpPostedFile = System.Web.HttpContext.Current.Request.Files[\"UploadFiles\"];\n if (httpPostedFile != null)\n {\n byte[] fileBytes;\n using (BinaryReader br = new BinaryReader(httpPostedFile.InputStream))\n {\n fileBytes = br.ReadBytes((int)httpPostedFile.InputStream.Length);\n // fileBytes now contains binary data — store in DB or process\n }\n HttpContext.Current.Response.StatusCode = 200;\n }\n }\n }\n catch (Exception e)\n {\n HttpContext.Current.Response.StatusCode = 204;\n HttpContext.Current.Response.StatusDescription = e.Message;\n }\n}\n```\n\n---\n\n## JWT Authentication\n\nSecure upload and remove requests by adding JWT tokens to request headers in the `uploading` and `removing` events.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const token = 'your.jwt.token'; // Replace with real token from your auth system\n\n const asyncSettings = {\n saveUrl: 'https://your-api.com/api/upload/save',\n removeUrl: 'https://your-api.com/api/upload/remove'\n };\n\n const onUploading = (args: any): void => {\n args.currentRequest.setRequestHeader('Authorization', `Bearer ${token}`);\n };\n\n const onRemoving = (args: any): void => {\n args.postRawFile = false; // Send file name only\n args.currentRequest.setRequestHeader('Authorization', `Bearer ${token}`);\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n uploading={onUploading}\n removing={onRemoving}\n />\n );\n}\n```\n\n**Server-side JWT validation (ASP.NET Core):**\n\n```csharp\nprivate bool IsAuthorized()\n{\n var authHeader = Request.Headers[\"Authorization\"].ToString();\n if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith(\"Bearer \"))\n return false;\n\n var token = authHeader[\"Bearer \".Length..];\n return ValidateToken(token); // Implement your token validation logic\n}\n\npublic async Task\u003cIActionResult> Save(IFormFile UploadFiles)\n{\n if (!IsAuthorized()) return Unauthorized();\n // Process file...\n return Ok();\n}\n```\n\n---\n\n## Form Support\n\n### HTML Form Integration\n\nIntegrate the Uploader as a standard file input within an HTML form.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n return (\n \u003cform action=\"/api/submit\" method=\"post\" encType=\"multipart/form-data\">\n \u003cUploaderComponent\n asyncSettings={{ saveUrl: '', removeUrl: '' }}\n autoUpload={false}\n htmlAttributes={{ name: 'uploadedFiles' }}\n />\n \u003cinput type=\"text\" name=\"userName\" placeholder=\"Your name\" />\n \u003cbutton type=\"submit\">Submit Form\u003c/button>\n \u003c/form>\n );\n}\n```\n\n> For HTML form integration: set `saveUrl` and `removeUrl` to empty strings, disable `autoUpload`, and add a `name` attribute via `htmlAttributes`.\n\n### React Hook Form Integration\n\n```tsx\nimport React from 'react';\nimport { useForm, Controller } from 'react-hook-form';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const { control, handleSubmit } = useForm();\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSubmit = (data: any) => console.log(data);\n\n return (\n \u003cform onSubmit={handleSubmit(onSubmit)}>\n \u003cController\n name=\"files\"\n control={control}\n render={({ field }) => (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n change={(args: any) => field.onChange(args.files)}\n />\n )}\n />\n \u003cbutton type=\"submit\">Submit\u003c/button>\n \u003c/form>\n );\n}\n```\n\n---\n\n## Localization\n\nCustomize all static text in the Uploader using the `L10n` library.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { L10n } from '@syncfusion/ej2-base';\n\n// Load custom locale before rendering\nL10n.load({\n 'fr-FR': {\n uploader: {\n Browse: 'Parcourir',\n Clear: 'Effacer',\n Upload: 'Télécharger',\n dropFilesHint: 'ou déposez des fichiers ici',\n uploadFailedMessage: 'Échec du téléchargement',\n uploadSuccessMessage: 'Téléchargement réussi',\n removedSuccessMessage: 'Fichier supprimé avec succès',\n removedFailedMessage: 'Impossible de supprimer le fichier',\n inProgress: 'En cours de téléchargement',\n readyToUploadMessage: 'Prêt à télécharger',\n pauseUpload: 'Téléchargement suspendu',\n fileUploadCancel: 'Téléchargement annulé',\n invalidMaxFileSize: 'La taille du fichier est trop grande',\n invalidFileType: 'Type de fichier non autorisé',\n invalidMinFileSize: 'La taille du fichier est trop petite',\n remove: 'Supprimer',\n cancel: 'Annuler',\n delete: 'Supprimer le fichier',\n totalFiles: 'Total des fichiers',\n size: 'Taille'\n }\n }\n});\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n locale=\"fr-FR\"\n />\n );\n}\n```\n\n**All localizable keys:**\n\n| Key | Description |\n|---|---|\n| `Browse` | Browse button text |\n| `Clear` | Clear button text |\n| `Upload` | Upload button text |\n| `dropFilesHint` | Drop area hint text |\n| `uploadFailedMessage` | Status on upload failure |\n| `uploadSuccessMessage` | Status on upload success |\n| `removedSuccessMessage` | Status on successful removal |\n| `removedFailedMessage` | Status on removal failure |\n| `inProgress` | Status while uploading |\n| `readyToUploadMessage` | Status when file is ready |\n| `pauseUpload` | Status when upload is paused |\n| `fileUploadCancel` | Status when upload is canceled |\n| `invalidMaxFileSize` | Validation: file too large |\n| `invalidFileType` | Validation: invalid file type |\n| `invalidMinFileSize` | Validation: file too small |\n| `remove` | Remove icon tooltip |\n| `cancel` | Cancel icon tooltip |\n| `delete` | Delete icon tooltip |\n| `totalFiles` | Total files tooltip |\n| `size` | Size tooltip |\n\n---\n\n## Accessibility\n\nThe Syncfusion React Uploader is fully accessible and complies with WCAG 2.2, Section 508, and ADA standards.\n\n**Compliance:**\n- WCAG 2.2 ✓\n- Section 508 ✓\n- Screen reader support ✓\n- RTL support (via `enableRtl`) ✓\n- Color contrast compliant ✓\n- Mobile device support ✓\n- Keyboard navigation ✓\n\n**Keyboard shortcuts:**\n\n| Key | Action |\n|---|---|\n| `Tab` | Move focus to the next element |\n| `Shift + Tab` | Move focus to the previous element |\n| `Enter` | Trigger the focused button action |\n| `Esc` | Close the file browser dialog / cancel |\n\n**RTL support:**\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n enableRtl={true}\n/>\n```\n\n**Security — HTML sanitizer:**\n\nThe `enableHtmlSanitizer` property (default: `true`) strips cross-site scripting code from filenames. Disable only if you fully trust the source.\n\n```tsx\n// Default: XSS prevention enabled\n\u003cUploaderComponent asyncSettings={asyncSettings} enableHtmlSanitizer={true} />\n```\n\n---\n\n## Get Total Size of Selected Files\n\nCalculate cumulative size of all files in the `selected` event.\n\n```tsx\nconst onSelected = (args: any): void => {\n const totalBytes = args.filesData.reduce((acc: number, f: any) => acc + f.size, 0);\n const totalSizeMB = (totalBytes / (1024 * 1024)).toFixed(2);\n console.log(`Total selected size: ${totalSizeMB} MB`);\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} selected={onSelected} />\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":20249,"content_sha256":"4f491891ebf89d934a8cfa1ec22d36f63e93cff09097da1c1ac683e1dc5d1e89"},{"filename":"references/uploader-api.md","content":"# API Reference – Syncfusion React UploaderComponent\n\n## Table of Contents\n- [Import](#import)\n- [Properties](#properties)\n- [Methods](#methods)\n- [Events](#events)\n- [Model Interfaces](#model-interfaces)\n\n---\n\n## Import\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n```\n\n**JSX usage:**\n```tsx\n\u003cUploaderComponent ref={uploaderRef} asyncSettings={asyncSettings} />\n```\n\n**Ref type:**\n```tsx\nimport React, { useRef } from 'react';\nconst uploaderRef = useRef\u003cUploaderComponent>(null);\n```\n\n---\n\n## Properties\n\n### allowedExtensions\n**Type:** `string` | **Default:** `''`\n\nSpecifies accepted file extensions as a comma-separated list with leading dots. Files not matching these extensions are rejected.\n\n```tsx\n\u003cUploaderComponent allowedExtensions=\".jpg,.png,.pdf,.docx\" />\n```\n\n---\n\n### asyncSettings\n**Type:** `AsyncSettingsModel` | **Default:** `{ saveUrl: '', removeUrl: '' }`\n\nConfigures the server URLs for save and remove operations, plus chunk upload settings.\n\n```tsx\nconst asyncSettings = {\n saveUrl: 'https://your-server.com/api/upload/save',\n removeUrl: 'https://your-server.com/api/upload/remove',\n chunkSize: 500000, // bytes per chunk; 0 = no chunking\n retryCount: 3, // retry attempts on chunk failure\n retryAfterDelay: 500 // ms delay between retries\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} />\n```\n\nSee [AsyncSettingsModel](#asyncsettingsmodel) for the full interface.\n\n---\n\n### autoUpload\n**Type:** `boolean` | **Default:** `true`\n\nWhen `true`, files upload immediately after selection. When `false`, Upload All and Clear All action buttons are displayed for manual control.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} autoUpload={false} />\n```\n\n---\n\n### buttons\n**Type:** `ButtonsPropsModel` | **Default:** `{ browse: 'Browse…', clear: 'Clear', upload: 'Upload' }`\n\nCustomizes the text or HTML content of the Browse, Clear, and Upload action buttons.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n buttons={{ browse: 'Choose File', clear: 'Clear All', upload: 'Upload All' }}\n/>\n```\n\nSee [ButtonsPropsModel](#buttonspropsmodel) for the interface.\n\n---\n\n### cssClass\n**Type:** `string` | **Default:** `''`\n\nAppends one or more custom CSS class names to the Uploader root element.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} cssClass=\"my-uploader compact\" />\n```\n\n---\n\n### directoryUpload\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, allows browsing and uploading an entire folder. All files in the selected directory and its subdirectories are uploaded. Individual file selection is disabled when this is `true`.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} directoryUpload={true} />\n```\n\n---\n\n### dropArea\n**Type:** `string | HTMLElement` | **Default:** `null`\n\nSpecifies an external element as the drag-and-drop target. Accepts an `HTMLElement` reference or a CSS selector string. By default, the component itself acts as the drop target.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} dropArea=\"#myDropZone\" />\n// or\n\u003cUploaderComponent asyncSettings={asyncSettings} dropArea={dropAreaRef.current} />\n```\n\n---\n\n### dropEffect\n**Type:** `DropEffect` | **Default:** `'Default'`\n\nControls the visual drag effect shown on the drop target. Possible values: `'Default'`, `'Copy'`, `'Move'`, `'Link'`, `'None'`.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} dropEffect=\"Copy\" />\n```\n\n---\n\n### enableHtmlSanitizer\n**Type:** `boolean` | **Default:** `true`\n\nWhen `true`, strips cross-site scripting (XSS) code from filenames and shows a validation error. Recommended to keep enabled.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} enableHtmlSanitizer={true} />\n```\n\n---\n\n### enablePersistence\n**Type:** `boolean` | **Default:** `false`\n\nEnables state persistence across page reloads.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} enablePersistence={true} />\n```\n\n---\n\n### enableRtl\n**Type:** `boolean` | **Default:** `false`\n\nRenders the component in right-to-left direction for RTL language support.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} enableRtl={true} />\n```\n\n---\n\n### enabled\n**Type:** `boolean` | **Default:** `true`\n\nEnables or disables the component. When `false`, all interactions are blocked.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} enabled={false} />\n```\n\n---\n\n### files\n**Type:** `FilesPropModel[]` | **Default:** `{ name: '', size: null, type: '' }`\n\nSpecifies a list of files preloaded on render (previously uploaded files). Required fields: `name`, `size`, `type`.\n\n```tsx\nconst preloadedFiles = [\n { name: 'Report', size: 120000, type: '.pdf' },\n { name: 'Image', size: 500000, type: '.png' }\n];\n\u003cUploaderComponent asyncSettings={asyncSettings} files={preloadedFiles} />\n```\n\nSee [FilesPropModel](#filespropmodel) for the interface.\n\n---\n\n### htmlAttributes\n**Type:** `{ [key: string]: string }` | **Default:** `{}`\n\nAdds arbitrary HTML attributes to the underlying file input element (e.g., `name`, `required`, `accept`).\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n htmlAttributes={{ name: 'uploadedFiles', required: 'required' }}\n/>\n```\n\n---\n\n### locale\n**Type:** `string` | **Default:** `''` (uses global culture `'en-US'`)\n\nOverrides the locale for this component instance. Load translations using `L10n.load()` before setting this.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} locale=\"fr-FR\" />\n```\n\n---\n\n### maxFileSize\n**Type:** `number` | **Default:** `30000000` (~28.6 MB)\n\nMaximum allowed upload file size in bytes. Files exceeding this limit are rejected with a validation error.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} maxFileSize={5242880} /> {/* 5 MB */}\n```\n\n---\n\n### minFileSize\n**Type:** `number` | **Default:** `0`\n\nMinimum required upload file size in bytes. Files below this limit are rejected.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} minFileSize={1024} /> {/* 1 KB min */}\n```\n\n---\n\n### multiple\n**Type:** `boolean` | **Default:** `true`\n\nAllows selecting and uploading multiple files when `true`. When `false`, only a single file can be selected at a time (new selection replaces the previous).\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} multiple={false} />\n```\n\n---\n\n### sequentialUpload\n**Type:** `boolean` | **Default:** `false`\n\nWhen `true`, uploads files one after another (sequentially) instead of simultaneously. The next file starts only after the previous succeeds or fails.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} sequentialUpload={true} />\n```\n\n---\n\n### showFileList\n**Type:** `boolean` | **Default:** `true`\n\nControls whether the default file list is rendered. Set to `false` to build a fully custom file list UI.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} showFileList={false} />\n```\n\n---\n\n### template\n**Type:** `string | Function` | **Default:** `null`\n\nSpecifies an HTML string or function to customize the appearance of each file item in the list.\n\n```tsx\nconst fileTemplate = () => {\n return (\n \u003cdiv className=\"file-row\">\n \u003cspan className=\"file-name\">${name}\u003c/span>\n \u003cspan className=\"file-size\">${size} bytes\u003c/span>\n \u003c/div>\n );\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} template={fileTemplate} />\n```\n\n---\n\n## Methods\n\nAll methods are accessed via a component `ref`.\n\n```tsx\nconst uploaderRef = useRef\u003cUploaderComponent>(null);\n// Access: uploaderRef.current?.methodName(...)\n```\n\n---\n\n### upload\n\n```ts\nupload(files?: FileInfo | FileInfo[], custom?: boolean): void\n```\n\nTriggers the upload process for specified files or all queued files.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `files` | `FileInfo \\| FileInfo[]` | Files to upload. If omitted, uploads all queued files. |\n| `custom` | `boolean` | Set `true` when using a custom file list UI (`showFileList={false}`). |\n\n```tsx\n// Upload all\nuploaderRef.current?.upload(uploaderRef.current.getFilesData());\n\n// Upload specific files\nuploaderRef.current?.upload([files[0]]);\n\n// Upload with custom UI\nuploaderRef.current?.upload(filesData, true);\n```\n\n---\n\n### remove\n\n```ts\nremove(fileData?: FileInfo | FileInfo[], customTemplate?: boolean, postRawFile?: boolean, args?: MouseEvent | TouchEvent | KeyboardEvent): void\n```\n\nRemoves a file from the list and optionally calls the remove URL to delete it from the server.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `fileData` | `FileInfo \\| FileInfo[]` | File(s) to remove. If omitted, clears all. |\n| `customTemplate` | `boolean` | Set `true` when using custom UI. |\n\n```tsx\nuploaderRef.current?.remove(filesData, true);\n```\n\n---\n\n### cancel\n\n```ts\ncancel(fileData?: FileInfo[]): void\n```\n\nCancels in-progress chunk uploads. Partially uploaded files are removed from the server.\n\n```tsx\nconst files = uploaderRef.current?.getFilesData();\nuploaderRef.current?.cancel(files);\n```\n\n---\n\n### pause\n\n```ts\npause(fileData?: FileInfo | FileInfo[], custom?: boolean): void\n```\n\nPauses in-progress chunk uploads. Only available when chunk upload is enabled.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `fileData` | `FileInfo \\| FileInfo[]` | File(s) to pause. |\n| `custom` | `boolean` | Set `true` for custom UI. |\n\n```tsx\nuploaderRef.current?.pause(files[0]);\n```\n\n---\n\n### resume\n\n```ts\nresume(fileData?: FileInfo | FileInfo[], custom?: boolean): void\n```\n\nResumes previously paused chunk uploads.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `fileData` | `FileInfo \\| FileInfo[]` | File(s) to resume. |\n| `custom` | `boolean` | Set `true` for custom UI. |\n\n```tsx\nuploaderRef.current?.resume(files[0]);\n```\n\n---\n\n### retry\n\n```ts\nretry(fileData?: FileInfo | FileInfo[], fromcanceledStage?: boolean, custom?: boolean): void\n```\n\nRetries a canceled or failed file upload.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `fileData` | `FileInfo \\| FileInfo[]` | File(s) to retry. |\n| `fromcanceledStage` | `boolean` | `true` = resume from failed chunk; `false` = restart from beginning. |\n| `custom` | `boolean` | Set `true` for custom UI. |\n\n```tsx\nuploaderRef.current?.retry(files, false); // Restart from beginning\nuploaderRef.current?.retry(files, true); // Resume from failed chunk\n```\n\n---\n\n### clearAll\n\n```ts\nclearAll(): void\n```\n\nClears all file entries from the list (both queued and uploaded).\n\n```tsx\nuploaderRef.current?.clearAll();\n```\n\n---\n\n### getFilesData\n\n```ts\ngetFilesData(index?: number): FileInfo[]\n```\n\nReturns the data of all files currently shown in the file list.\n\n| Parameter | Type | Description |\n|---|---|---|\n| `index` | `number` | Optional. Returns only the file at the specified list index. |\n\n```tsx\nconst allFiles = uploaderRef.current?.getFilesData();\nconst firstFile = uploaderRef.current?.getFilesData(0);\n```\n\n---\n\n### bytesToSize\n\n```ts\nbytesToSize(bytes: number): string\n```\n\nConverts a byte value to a human-readable string using binary prefix (KB, MB, GB).\n\n```tsx\nconst size = uploaderRef.current?.bytesToSize(1048576); // \"1 MB\"\n```\n\n---\n\n### createFileList\n\n```ts\ncreateFileList(fileData: FileInfo[]): void\n```\n\nCreates file list items in the UI for the specified file data array.\n\n```tsx\nuploaderRef.current?.createFileList(filesData);\n```\n\n---\n\n### sortFileList\n\n```ts\nsortFileList(filesData?: FileList): File[]\n```\n\nSorts file data alphabetically by file name.\n\n```tsx\nconst sorted = uploaderRef.current?.sortFileList(rawFileList);\n```\n\n---\n\n### getModuleName\n\n```ts\ngetModuleName(): string\n```\n\nReturns the module name of the component (`'uploader'`).\n\n---\n\n### destroy\n\n```ts\ndestroy(): void\n```\n\nRemoves the component from the DOM and detaches all event handlers, attributes, and classes.\n\n```tsx\nuploaderRef.current?.destroy();\n```\n\n---\n\n## Events\n\nAll events are passed as props to `UploaderComponent`.\n\n---\n\n### uploading\n**Type:** `EmitType\u003cUploadingEventArgs>`\n\nFires when each file upload process starts. Use to add custom headers or form data.\n\n```tsx\nconst onUploading = (args: any): void => {\n args.currentRequest.setRequestHeader('Authorization', 'Bearer ' + token);\n args.customFormData = [{ key: 'value' }];\n // args.cancel = true; // Cancel this upload\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} uploading={onUploading} />\n```\n\n**Key args:** `currentRequest` (XMLHttpRequest), `customFormData`, `fileData`, `cancel`\n\n---\n\n### success\n**Type:** `EmitType\u003cObject>`\n\nFires when an upload or remove operation completes successfully.\n\n```tsx\nconst onSuccess = (args: any): void => {\n // args.operation: 'upload' | 'remove'\n // args.file: FileInfo\n // args.event: Ajax progress event\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} success={onSuccess} />\n```\n\n---\n\n### failure\n**Type:** `EmitType\u003cObject>`\n\nFires when an upload or remove operation fails.\n\n```tsx\nconst onFailure = (args: any): void => {\n // args.operation: 'upload' | 'remove'\n // args.file: FileInfo\n // args.event: Ajax progress event\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} failure={onFailure} />\n```\n\n---\n\n### selected\n**Type:** `EmitType\u003cSelectedEventArgs>`\n\nFires after files are selected or dropped, before they are added to the upload queue.\n\n```tsx\nconst onSelected = (args: any): void => {\n // args.filesData: FileInfo[] — selected files\n // args.modifiedFilesData: FileInfo[] — set to filter/sort files\n // args.cancel = true; — cancel adding files to queue\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} selected={onSelected} />\n```\n\n---\n\n### removing\n**Type:** `EmitType\u003cRemovingEventArgs>`\n\nFires before a file is removed from the server. Use to set `postRawFile` or add headers.\n\n```tsx\nconst onRemoving = (args: any): void => {\n args.postRawFile = false; // Send only file name, not raw file\n args.currentRequest.setRequestHeader('Authorization', 'Bearer ' + token);\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} removing={onRemoving} />\n```\n\n---\n\n### beforeRemove\n**Type:** `EmitType\u003cBeforeRemoveEventArgs>`\n\nFires before the removal request is sent to the server. Use to confirm or cancel removal.\n\n```tsx\nconst onBeforeRemove = (args: any): void => {\n args.cancel = !window.confirm('Remove this file?');\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} beforeRemove={onBeforeRemove} />\n```\n\n---\n\n### beforeUpload\n**Type:** `EmitType\u003cBeforeUploadEventArgs>`\n\nFires before the upload process starts. Use to add additional parameters.\n\n```tsx\nconst onBeforeUpload = (args: any): void => {\n // Inspect or modify before upload begins\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} beforeUpload={onBeforeUpload} />\n```\n\n---\n\n### change\n**Type:** `EmitType\u003cObject>`\n\nFires when the file list changes (files added or removed).\n\n```tsx\nconst onChange = (args: any): void => {\n // args.file: FileInfo — file added or removed\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} change={onChange} />\n```\n\n---\n\n### progress\n**Type:** `EmitType\u003cObject>`\n\nFires during upload to report progress.\n\n```tsx\nconst onProgress = (args: any): void => {\n const percent = Math.round((args.e.loaded / args.e.total) * 100);\n console.log(`${args.file.name}: ${percent}%`);\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} progress={onProgress} />\n```\n\n**Key args:** `e` (Ajax progress event with `loaded`/`total`), `file` (FileInfo), `name`\n\n---\n\n### chunkSuccess\n**Type:** `EmitType\u003cObject>`\n\nFires when each chunk uploads successfully.\n\n```tsx\nconst onChunkSuccess = (args: any): void => {\n // args.chunkIndex, args.chunkSize, args.file, args.totalChunk\n console.log(`Chunk ${args.chunkIndex + 1}/${args.totalChunk} done`);\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} chunkSuccess={onChunkSuccess} />\n```\n\n---\n\n### chunkFailure\n**Type:** `EmitType\u003cObject>`\n\nFires when a chunk fails to upload.\n\n```tsx\nconst onChunkFailure = (args: any): void => {\n // args.chunkIndex, args.file, args.totalChunk\n // args.cancel = true; — prevent triggering the failure event\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} chunkFailure={onChunkFailure} />\n```\n\n---\n\n### chunkUploading\n**Type:** `EmitType\u003cUploadingEventArgs>`\n\nFires before each chunk upload starts. Use to add headers per chunk.\n\n```tsx\nconst onChunkUploading = (args: any): void => {\n args.currentRequest.setRequestHeader('X-Chunk-Index', args.chunkIndex);\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} chunkUploading={onChunkUploading} />\n```\n\n---\n\n### actionComplete\n**Type:** `EmitType\u003cActionCompleteEventArgs>`\n\nFires after all selected files have either uploaded successfully or failed.\n\n```tsx\nconst onActionComplete = (args: any): void => {\n console.log('All uploads complete. Files:', args.fileData);\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} actionComplete={onActionComplete} />\n```\n\n---\n\n### canceling\n**Type:** `EmitType\u003cCancelEventArgs>`\n\nFires when a chunk upload is canceled.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} canceling={(args) => console.log('Canceled:', args)} />\n```\n\n---\n\n### clearing\n**Type:** `EmitType\u003cClearingEventArgs>`\n\nFires before the file list is cleared (when the Clear button is clicked).\n\n```tsx\nconst onClearing = (args: any): void => {\n // args.cancel = true; — prevent clearing\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} clearing={onClearing} />\n```\n\n---\n\n### created\n**Type:** `EmitType\u003cObject>`\n\nFires when the component is created and fully initialized.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} created={() => console.log('Uploader ready')} />\n```\n\n---\n\n### fileListRendering\n**Type:** `EmitType\u003cFileListRenderingEventArgs>`\n\nFires before each file item is rendered in the list. Use to customize individual list items.\n\n```tsx\nconst onFileListRendering = (args: any): void => {\n // args.element — the LI element\n // args.fileInfo — FileInfo for this item\n if (args.fileInfo.size > 1000000) {\n args.element.classList.add('large-file');\n }\n};\n\u003cUploaderComponent asyncSettings={asyncSettings} fileListRendering={onFileListRendering} />\n```\n\n---\n\n### pausing\n**Type:** `EmitType\u003cPauseResumeEventArgs>`\n\nFires when a chunk upload is paused.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} pausing={(args) => console.log('Paused:', args.file.name)} />\n```\n\n---\n\n### resuming\n**Type:** `EmitType\u003cPauseResumeEventArgs>`\n\nFires when a paused chunk upload resumes.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} resuming={(args) => console.log('Resumed:', args.file.name)} />\n```\n\n---\n\n### rendering *(deprecated)*\n**Type:** `EmitType\u003cRenderingEventArgs>`\n\n> **Deprecated.** Use `fileListRendering` instead.\n\n---\n\n## Model Interfaces\n\n### AsyncSettingsModel\n\n```ts\ninterface AsyncSettingsModel {\n saveUrl?: string; // URL to handle file save on server\n removeUrl?: string; // URL to handle file removal from server\n chunkSize?: number; // Chunk size in bytes (0 = disabled)\n retryCount?: number; // Retry attempts on chunk failure (default: 3)\n retryAfterDelay?: number; // Delay in ms before retry (default: 500)\n}\n```\n\n---\n\n### ButtonsPropsModel\n\n```ts\ninterface ButtonsPropsModel {\n browse?: string | HTMLElement; // Browse button text/element\n clear?: string | HTMLElement; // Clear button text/element\n upload?: string | HTMLElement; // Upload button text/element\n}\n```\n\n---\n\n### FilesPropModel\n\n```ts\ninterface FilesPropModel {\n name?: string; // Required: file name (without path)\n size?: number; // Required: file size in bytes\n type?: string; // Required: file extension (e.g., '.pdf')\n}\n```\n\n---\n\n### FileInfo\n\n```ts\ninterface FileInfo {\n name: string; // File name\n size: number; // File size in bytes\n type: string; // File extension\n status: string; // Current status string\n statusCode: string; // '1' = ready, '2' = uploading, '3' = success, '4' = failed\n rawFile: File | string; // Raw File object (or string for preloaded)\n validationMessage: string;// Validation error message (if any)\n id?: string; // Unique identifier\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":20017,"content_sha256":"9ab49cac9e57227f781e2618df6b40b8fbbc270a6942c6b102979f51d7462667"},{"filename":"references/uploader-async-upload.md","content":"# Asynchronous File Upload – Syncfusion React Uploader\n\n## Table of Contents\n- [Overview](#overview)\n- [asyncSettings Configuration](#asyncsettings-configuration)\n- [Multiple File Upload](#multiple-file-upload)\n- [Single File Upload](#single-file-upload)\n- [Save Action](#save-action)\n- [Remove Action](#remove-action)\n- [Auto Upload](#auto-upload)\n- [Sequential Upload](#sequential-upload)\n- [Preloaded Files](#preloaded-files)\n- [Adding Custom HTTP Headers](#adding-custom-http-headers)\n- [Adding Custom Form Data](#adding-custom-form-data)\n- [Server-Side Examples](#server-side-examples)\n\n---\n\n## Overview\n\nThe Uploader supports asynchronous file uploads. Configure `asyncSettings` with `saveUrl` and optionally `removeUrl` to handle server operations. Files can be uploaded automatically or manually.\n\n---\n\n## asyncSettings Configuration\n\n`asyncSettings` is an `AsyncSettingsModel` object with the following fields:\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `saveUrl` | `string` | `''` | URL to handle file save on the server |\n| `removeUrl` | `string` | `''` | URL to handle file removal from the server |\n| `chunkSize` | `number` | `0` | Size of each chunk in bytes (0 = no chunking) |\n| `retryCount` | `number` | `3` | Number of retry attempts for failed chunk uploads |\n| `retryAfterDelay` | `number` | `500` | Delay in milliseconds before retrying a failed chunk |\n\n```tsx\nconst asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} />\n```\n\n---\n\n## Multiple File Upload\n\nBy default, `multiple` is `true`. Users can select and upload multiple files simultaneously. Selected files appear in a list and persist until cleared.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n multiple={true}\n/>\n```\n\n> The `multiple` attribute is added to the underlying `\u003cinput>` element when `multiple={true}`.\n\n---\n\n## Single File Upload\n\nSet `multiple={false}` to restrict selection to one file at a time. Each new selection replaces the previous file in the list.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n multiple={false}\n/>\n```\n\n---\n\n## Save Action\n\nThe `saveUrl` handler processes uploaded files on the server. After a successful upload, the file name turns green. Use the `success` and `failure` events to handle outcomes.\n\n```tsx\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSuccess = (args: any): void => {\n console.log(`${args.operation} succeeded:`, args.file.name);\n };\n\n const onFailure = (args: any): void => {\n console.error(`${args.operation} failed:`, args.file.name);\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n success={onSuccess}\n failure={onFailure}\n />\n );\n}\n```\n\n> Differentiate upload vs. remove by checking `args.operation` (`'upload'` or `'remove'`).\n\n**Cancel upload in the `uploading` event** by setting `args.cancel = true`:\n\n```tsx\nconst onUploading = (args: any): void => {\n if (someCondition) {\n args.cancel = true; // Cancel this upload\n }\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} uploading={onUploading} />\n```\n\n---\n\n## Remove Action\n\n`removeUrl` is optional. When provided, clicking the delete icon sends a remove request to the server.\n\n```tsx\nconst asyncSettings = {\n saveUrl: '/api/upload/save',\n removeUrl: '/api/upload/remove'\n};\n\n// Only send file name (not full file data) to the server\nconst onRemoving = (args: any): void => {\n args.postRawFile = false; // Send file name only\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} removing={onRemoving} />\n```\n\n> When `postRawFile` is `true` (default), the full file binary is sent to the remove URL. Set it to `false` to send only the file name.\n\nFiles not yet uploaded to the server can be removed without triggering `success`/`failure` events.\n\n---\n\n## Auto Upload\n\nBy default, `autoUpload` is `true` — files start uploading immediately on selection. Set `autoUpload={false}` to show Upload All / Clear All action buttons for manual control.\n\n```tsx\n// Manual upload — shows \"Upload\" and \"Clear\" buttons\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n buttons={{ browse: 'Choose File', clear: 'Clear All', upload: 'Upload All' }}\n/>\n```\n\n---\n\n## Sequential Upload\n\nBy default, multiple files upload in parallel. Enable `sequentialUpload` to upload one file at a time. The next file starts only after the current one succeeds or fails — reducing server traffic and upload failures.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n/>\n```\n\n---\n\n## Preloaded Files\n\nUse the `files` prop to display previously uploaded files on render. Users can view and remove them without re-uploading. Required fields per file: `name`, `size`, `type`.\n\n```tsx\nimport * as React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const preloadedFiles = [\n { name: 'Nature', size: 500000, type: '.png' },\n { name: 'Report', size: 120000, type: '.pdf' },\n { name: 'Specs', size: 45000, type: '.docx' }\n ];\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n files={preloadedFiles}\n />\n );\n}\n```\n\n> Preloaded files are rendered with \"uploaded successfully\" status by default.\n\n---\n\n## Adding Custom HTTP Headers\n\nUse the `uploading` and `removing` events to add request headers (e.g., auth tokens) via `args.currentRequest.setRequestHeader()`.\n\n```tsx\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const addHeaders = (args: any): void => {\n args.currentRequest.setRequestHeader('custom-header', 'Syncfusion');\n // Or add auth token:\n // args.currentRequest.setRequestHeader('Authorization', 'Bearer ' + token);\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n uploading={addHeaders}\n removing={addHeaders}\n />\n );\n}\n```\n\n---\n\n## Adding Custom Form Data\n\nSend additional key-value pairs with each upload request using `args.customFormData` in the `uploading` event.\n\n```tsx\nconst onUploading = (args: any): void => {\n // Add extra form fields to the upload request\n args.customFormData = [{ companyName: 'Syncfusion INC' }, { userId: '12345' }];\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} uploading={onUploading} />\n```\n\n**Server-side retrieval (C#):**\n```csharp\nvar companyName = HttpContext.Current.Request.Form[\"companyName\"];\nvar userId = HttpContext.Current.Request.Form[\"userId\"];\n```\n\n---\n\n## Server-Side Examples\n\n### Save Action (ASP.NET Core)\n\n```csharp\npublic async Task\u003cIActionResult> Save(IFormFile UploadFiles)\n{\n if (UploadFiles.Length > 0)\n {\n if (!Directory.Exists(uploads))\n Directory.CreateDirectory(uploads);\n\n var filePath = Path.Combine(uploads, UploadFiles.FileName);\n using (var fileStream = new FileStream(filePath, FileMode.Create))\n {\n await UploadFiles.CopyToAsync(fileStream);\n }\n }\n return Ok();\n}\n```\n\n### Remove Action (ASP.NET Core)\n\n```csharp\npublic void Remove(string UploadFiles)\n{\n if (UploadFiles != null)\n {\n var filePath = Path.Combine(uploads, UploadFiles);\n if (System.IO.File.Exists(filePath))\n System.IO.File.Delete(filePath);\n }\n}\n```\n\n### Returning JSON/String/File Response\n\n```csharp\n[AcceptVerbs(\"Post\")]\npublic IActionResult Save()\n{\n // JSON response\n try {\n return Json(new { Success = true, Message = \"Files uploaded successfully\" });\n }\n catch (Exception e) {\n return Json(new { Success = false, Message = \"Upload failed: \" + e.Message });\n }\n}\n```\n\n---\n\n## Gotchas\n\n- **`saveUrl` is required** for async upload to work; without it, files cannot be uploaded.\n- **`removeUrl` is optional** — if omitted, the delete icon still appears but no server call is made.\n- **`autoUpload` defaults to `true`** — set it to `false` explicitly to show manual Upload/Clear buttons.\n- **`postRawFile` defaults to `true`** — set to `false` in the `removing` event to send only the filename.\n- **Sequential vs. parallel** — parallel is the default; sequential is safer for server rate limits.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8877,"content_sha256":"dc027b91d08a7f8d17837bcb763d770295379286ec98a623977e0edbe4e452d4"},{"filename":"references/uploader-chunk-upload.md","content":"# Chunk Upload – Syncfusion React Uploader\n\n## Table of Contents\n- [Overview](#overview)\n- [Enabling Chunk Upload](#enabling-chunk-upload)\n- [Retry Configuration](#retry-configuration)\n- [Pause and Resume](#pause-and-resume)\n- [Cancel Upload](#cancel-upload)\n- [Chunk Events](#chunk-events)\n- [Server-Side Configuration](#server-side-configuration)\n- [Gotchas](#gotchas)\n\n---\n\n## Overview\n\nChunk upload splits large files into smaller pieces and transmits them sequentially to the server using AJAX. Chunks are sent in order; if one fails, subsequent chunks are not sent. Chunk upload also enables pause, resume, and retry for interrupted uploads.\n\n> - Chunk upload works **only in asynchronous mode** (with `asyncSettings.saveUrl`).\n> - Only files **larger than `chunkSize`** are chunked. Smaller files upload normally.\n> - Pause/Resume is available **only when chunk upload is enabled**.\n\n---\n\n## Enabling Chunk Upload\n\nSet `asyncSettings.chunkSize` to a positive byte value to activate chunking.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove',\n chunkSize: 500000 // 500 KB per chunk\n };\n\n return \u003cUploaderComponent asyncSettings={asyncSettings} />;\n}\n```\n\n> `chunkSize` is specified in **bytes**. Example: `500000` = 500 KB, `1000000` = 1 MB.\n\n---\n\n## Retry Configuration\n\nControl retry behavior for failed chunks using `retryCount` and `retryAfterDelay`:\n\n| Property | Default | Description |\n|---|---|---|\n| `retryCount` | `3` | Number of retry attempts before triggering `failure` |\n| `retryAfterDelay` | `500` | Milliseconds to wait before each retry |\n\n```tsx\nconst asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove',\n chunkSize: 500000,\n retryCount: 5, // Retry up to 5 times\n retryAfterDelay: 3000 // Wait 3 seconds between retries\n};\n\n\u003cUploaderComponent asyncSettings={asyncSettings} />\n```\n\n> After all retries are exhausted, the upload aborts and the `failure` event fires.\n\n---\n\n## Pause and Resume\n\nPause and resume in-progress chunk uploads programmatically using the `pause` and `resume` methods, or via the UI pause icon (appears once upload begins).\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove',\n chunkSize: 500000\n };\n\n const handlePause = (): void => {\n const files = uploaderRef.current?.getFilesData();\n if (files && files.length > 0) {\n uploaderRef.current?.pause(files[0]); // Pause the first file\n }\n };\n\n const handleResume = (): void => {\n const files = uploaderRef.current?.getFilesData();\n if (files && files.length > 0) {\n uploaderRef.current?.resume(files[0]); // Resume the first file\n }\n };\n\n return (\n \u003cdiv>\n \u003cUploaderComponent ref={uploaderRef} asyncSettings={asyncSettings} />\n \u003cbutton onClick={handlePause}>Pause\u003c/button>\n \u003cbutton onClick={handleResume}>Resume\u003c/button>\n \u003c/div>\n );\n}\n```\n\n**Method signatures:**\n- `pause(fileData?: FileInfo | FileInfo[], custom?: boolean): void`\n- `resume(fileData?: FileInfo | FileInfo[], custom?: boolean): void`\n\nSet `custom = true` when using a custom file list UI.\n\n---\n\n## Cancel Upload\n\nCancel an in-progress chunk upload using the `cancel` method or the UI cancel icon. When canceled, the partially uploaded file is removed from the server.\n\n```tsx\nconst handleCancel = (): void => {\n const files = uploaderRef.current?.getFilesData();\n if (files && files.length > 0) {\n uploaderRef.current?.cancel(files); // Cancel all or specific file(s)\n }\n};\n```\n\n**After canceling:** The pause icon changes to a retry icon in the UI. Users can click retry to restart the upload from the beginning.\n\n**Retry a canceled file:**\n```tsx\nconst handleRetry = (): void => {\n const files = uploaderRef.current?.getFilesData();\n if (files) {\n // fromcanceledStage=false → restart from the beginning\n uploaderRef.current?.retry(files, false);\n }\n};\n```\n\n**Method signature:**\n- `cancel(fileData?: FileInfo[]): void`\n- `retry(fileData?: FileInfo | FileInfo[], fromcanceledStage?: boolean, custom?: boolean): void`\n\n> **Retry behavior difference:**\n> - Chunk upload: Resumes from the failed chunk (when `fromcanceledStage=true`)\n> - Default upload: Always restarts from the beginning\n\n---\n\n## Chunk Events\n\n| Event | Trigger |\n|---|---|\n| `chunkSuccess` | Each chunk successfully uploaded |\n| `chunkFailure` | A chunk failed to upload |\n| `chunkUploading` | Before each chunk upload starts (add params here) |\n| `pausing` | When a chunk upload is paused |\n| `resuming` | When a paused chunk upload resumes |\n| `canceling` | When an upload is canceled |\n| `success` | All chunks uploaded successfully (entire file complete) |\n| `failure` | All retries exhausted, file upload failed |\n\n```tsx\nconst onChunkSuccess = (args: any): void => {\n console.log(`Chunk ${args.chunkIndex + 1} of ${args.totalChunk} uploaded`);\n console.log('Chunk size:', args.chunkSize);\n};\n\nconst onChunkFailure = (args: any): void => {\n console.error(`Chunk ${args.chunkIndex} failed for:`, args.file.name);\n // Set args.cancel = true to prevent triggering the failure event\n};\n\nconst onChunkUploading = (args: any): void => {\n // Add custom headers for each chunk request\n args.currentRequest.setRequestHeader('chunk-custom', 'value');\n};\n\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n chunkSuccess={onChunkSuccess}\n chunkFailure={onChunkFailure}\n chunkUploading={onChunkUploading}\n/>\n```\n\n**`chunkSuccess` / `chunkFailure` event arguments:**\n\n| Argument | Description |\n|---|---|\n| `chunkIndex` | Current chunk index (0-based) |\n| `chunkSize` | Size of the current chunk in bytes |\n| `file` | FileInfo of the uploading file |\n| `totalChunk` | Total number of chunks for this file |\n| `cancel` (chunkFailure only) | Set `true` to prevent triggering the `failure` event |\n\n---\n\n## Server-Side Configuration\n\nThe server receives chunk data with form fields `chunk-index` and `total-chunk`. Use these to reconstruct the file from parts.\n\n```csharp\npublic async Task\u003cIActionResult> Save(IFormFile UploadFiles)\n{\n try\n {\n if (UploadFiles.Length > 0)\n {\n var fileName = UploadFiles.FileName;\n\n if (!Directory.Exists(uploads))\n Directory.CreateDirectory(uploads);\n\n if (UploadFiles.ContentType == \"application/octet-stream\") // Chunk upload\n {\n var chunkIndex = Request.Form[\"chunk-index\"];\n var totalChunk = Request.Form[\"total-chunk\"];\n var tempFilePath = Path.Combine(uploads, fileName + \".part\");\n\n // Append or create file\n using (var fileStream = new FileStream(\n tempFilePath,\n chunkIndex == \"0\" ? FileMode.Create : FileMode.Append))\n {\n await UploadFiles.CopyToAsync(fileStream);\n }\n\n // Last chunk — move to final path\n if (Convert.ToInt32(chunkIndex) == Convert.ToInt32(totalChunk) - 1)\n {\n var finalPath = Path.Combine(uploads, fileName);\n System.IO.File.Move(tempFilePath, finalPath);\n return Ok(new { status = \"File uploaded successfully\" });\n }\n\n return Ok(new { status = \"Chunk uploaded\" });\n }\n else // Normal upload\n {\n var filePath = Path.Combine(uploads, fileName);\n using (var fileStream = new FileStream(filePath, FileMode.Create))\n {\n await UploadFiles.CopyToAsync(fileStream);\n }\n return Ok(new { status = \"File uploaded successfully\" });\n }\n }\n return BadRequest(new { status = \"No file\" });\n }\n catch (Exception ex)\n {\n return StatusCode(500, new { status = \"Error\", message = ex.Message });\n }\n}\n```\n\n> Access chunk metadata from form data:\n> - `Request.Form[\"chunk-index\"]` — Zero-based index of the current chunk\n> - `Request.Form[\"total-chunk\"]` — Total number of chunks for the file\n\n---\n\n## Gotchas\n\n- **`chunkSize` must be positive** — `chunkSize: 0` disables chunking entirely.\n- **Chunk upload is sequential** — Chunks are sent one at a time; the next chunk only starts after the previous succeeds.\n- **Files smaller than `chunkSize`** upload normally without chunking.\n- **Pause/Resume requires chunk upload** — These features do nothing without `chunkSize`.\n- **`cancel` removes partial file** — The server should handle incomplete `.part` files; partially uploaded chunks are removed.\n- **Retry from canceled stage** — Pass `fromcanceledStage=true` to `retry()` to resume from the failed chunk; `false` restarts from the beginning.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9431,"content_sha256":"0f14f6522235d15a83b4346f061b02a9e2933259938d576225dfbac2c3247dc6"},{"filename":"references/uploader-events.md","content":"# Uploader Events\n\n## Table of Contents\n- [Event Reference](#event-reference)\n- [Lifecycle Events](#lifecycle-events)\n- [Selection Events](#selection-events)\n- [Pre-Upload Events](#pre-upload-events)\n- [Upload Progress Events](#upload-progress-events)\n- [Post-Upload Events](#post-upload-events)\n- [Remove Events](#remove-events)\n- [State Change Events](#state-change-events)\n- [Chunk Upload Events](#chunk-upload-events)\n- [Common Patterns](#common-patterns)\n\n---\n\n## Event Reference\n\n| Event | Type | Cancelable | When it fires |\n|-------|------|-----------|---------------|\n| `created` | `EmitType\u003cObject>` | No | Component rendered in DOM |\n| `selected` | `EmitType\u003cSelectedEventArgs>` | No | Files selected or dropped |\n| `rendering` | `EmitType\u003cRenderingEventArgs>` | Yes | Before each file item renders in list |\n| `beforeUpload` | `EmitType\u003cBeforeUploadEventArgs>` | Yes | Before upload request is sent |\n| `uploading` | `EmitType\u003cUploadingEventArgs>` | Yes | Immediately before each file is sent (add headers here) |\n| `progress` | `EmitType\u003cProgressEventArgs>` | No | During upload — fires repeatedly as data transfers |\n| `success` | `EmitType\u003cSuccessEventArgs>` | No | After file uploads or removes successfully |\n| `failure` | `EmitType\u003cFailureEventArgs>` | No | After file upload/remove fails |\n| `removing` | `EmitType\u003cRemovingEventArgs>` | Yes | Before a file is removed |\n| `fileRemoved` | `EmitType\u003cRemovingEventArgs>` | No | After a file is removed from the list |\n| `clearing` | `EmitType\u003cClearingEventArgs>` | Yes | Before all files are cleared |\n| `cleared` | `EmitType\u003cObject>` | No | After all files are cleared |\n| `canceling` | `EmitType\u003cCancelEventArgs>` | No | When upload is cancelled |\n| `actionComplete` | `EmitType\u003cActionCompleteEventArgs>` | No | After all queued uploads/removes complete |\n| `chunkSuccess` | `EmitType\u003cObject>` | No | After each chunk successfully uploads |\n| `chunkFailure` | `EmitType\u003cObject>` | No | After a chunk upload fails |\n| `pausing` | `EmitType\u003cPauseResumeEventArgs>` | No | When chunk upload is paused |\n| `resuming` | `EmitType\u003cPauseResumeEventArgs>` | No | When chunk upload resumes |\n\n---\n\n## Lifecycle Events\n\n### `created`\nFires after the component mounts. Use to configure drop areas or initialize external state.\n\n```tsx\nfunction onCreated() {\n console.log('Uploader ready');\n // Safe to call .dropArea = ... here\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} created={onCreated} />\n```\n\n### `actionComplete`\nFires once after **all** upload/remove operations in the current batch finish. Provides a summary of all processed files.\n\n```tsx\nimport { ActionCompleteEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onActionComplete(args: ActionCompleteEventArgs) {\n const succeeded = args.filesData.filter(f => f.statusCode === '3').length;\n const failed = args.filesData.filter(f => f.statusCode === '0').length;\n console.log(`Complete — ${succeeded} succeeded, ${failed} failed`);\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} actionComplete={onActionComplete} />\n```\n\n---\n\n## Selection Events\n\n### `selected`\nFires after the user selects or drops files. Modify the file list here before upload starts.\n\n```tsx\nimport { SelectedEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onSelected(args: SelectedEventArgs) {\n // args.filesData — newly selected files\n // args.modifiedFilesData — set this to override the final file list\n // args.isModified — must be true for modifiedFilesData to take effect\n\n // Example: filter to images only\n args.filesData = args.filesData.filter(f => (f.rawFile as File).type.startsWith('image/'));\n args.modifiedFilesData = args.filesData;\n args.isModified = true;\n}\n```\n\n> `args.modifiedFilesData` requires `args.isModified = true` to be honoured.\n\n### `rendering`\nFires before each file item is rendered in the list. Cancel to prevent a specific item from appearing.\n\n```tsx\nimport { RenderingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onRendering(args: RenderingEventArgs) {\n if (args.fileInfo.name.startsWith('_')) {\n args.cancel = true; // hide files starting with underscore\n }\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} rendering={onRendering} />\n```\n\n---\n\n## Pre-Upload Events\n\n### `beforeUpload`\nFires before the upload request is initiated. Cancel here to block the upload entirely.\n\n```tsx\nimport { BeforeUploadEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onBeforeUpload(args: BeforeUploadEventArgs) {\n if (!isUserAuthenticated()) {\n args.cancel = true;\n alert('Please log in before uploading files.');\n }\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} beforeUpload={onBeforeUpload} />\n```\n\n### `uploading`\nFires immediately before each file request is sent. The best place to add custom HTTP headers, inject form data, or perform last-minute validation.\n\n```tsx\nimport { UploadingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onUploading(args: UploadingEventArgs) {\n // Add authentication header\n (args.currentRequest as XMLHttpRequest).setRequestHeader('Authorization', `Bearer ${token}`);\n\n // Attach additional form data\n args.customFormData = [\n { userId: currentUser.id },\n { uploadedAt: new Date().toISOString() },\n ];\n\n // Cancel if needed\n if (args.fileData.size > 10_000_000) {\n args.cancel = true;\n }\n}\n```\n\nKey `UploadingEventArgs` properties:\n- `currentRequest` — the `XMLHttpRequest` object (set headers here)\n- `fileData` — the `FileInfo` for the file being uploaded\n- `customFormData` — array of key-value objects to append to the form data\n- `cancel` — set to `true` to abort this upload\n\n---\n\n## Upload Progress Events\n\n### `progress`\nFires repeatedly during file transfer. Use to build custom progress indicators.\n\n```tsx\nimport { ProgressEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onProgress(args: ProgressEventArgs) {\n const percent = Math.round((args.e.loaded / args.e.total) * 100);\n console.log(`${args.file.name}: ${percent}%`);\n // Update your own progress bar state here\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} progress={onProgress} />\n```\n\n---\n\n## Post-Upload Events\n\n### `success`\nFires after a file uploads or is removed successfully. Differentiate with `args.operation`.\n\n```tsx\nimport { SuccessEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onSuccess(args: SuccessEventArgs) {\n if (args.operation === 'upload') {\n console.log('Uploaded:', args.file?.name);\n // Parse server response\n const response = JSON.parse((args.e?.target as XMLHttpRequest).responseText || '{}');\n } else if (args.operation === 'remove') {\n console.log('Removed from server:', args.file?.name);\n }\n}\n```\n\n### `failure`\nFires when an upload or remove request fails (after all retries are exhausted for chunk uploads).\n\n```tsx\nimport { FailureEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onFailure(args: FailureEventArgs) {\n console.error(`Failed: ${args.file?.name}`, {\n statusCode: args.statusCode,\n statusText: args.statusText,\n operation: args.operation,\n });\n}\n```\n\n---\n\n## Remove Events\n\n### `removing`\nFires before a file is removed. Cancel to prevent removal (e.g., show a confirm dialog first).\n\n```tsx\nimport { RemovingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onRemoving(args: RemovingEventArgs) {\n // Send only filename to server (not raw file binary)\n args.postRawFile = false;\n\n // Block removal with a confirm\n if (!window.confirm(`Remove ${args.filesData[0]?.name}?`)) {\n args.cancel = true;\n }\n}\n\u003cUploaderComponent asyncSettings={asyncSettings} removing={onRemoving} />\n```\n\n### `fileRemoved`\nFires after a file is removed from the list (local or server).\n\n```tsx\nfunction onFileRemoved(args: RemovingEventArgs) {\n console.log('File removed from list:', args.filesData[0]?.name);\n}\n```\n\n---\n\n## State Change Events\n\n### `clearing` / `cleared`\n`clearing` fires before the Clear All button action — cancel to prevent it. `cleared` fires after all files are removed.\n\n```tsx\nimport { ClearingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onClearing(args: ClearingEventArgs) {\n if (!window.confirm('Clear all files?')) {\n args.cancel = true;\n }\n}\n\nfunction onCleared() {\n console.log('File list cleared');\n}\n\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n clearing={onClearing}\n cleared={onCleared}\n/>\n```\n\n### `canceling`\nFires when an in-progress upload is cancelled (e.g., via the cancel icon).\n\n```tsx\nfunction onCanceling(args: any) {\n console.log('Upload cancelled:', args.fileData?.name);\n}\n```\n\n---\n\n## Chunk Upload Events\n\n### `chunkSuccess` / `chunkFailure`\nFire after each chunk succeeds or fails during chunk upload.\n\n```tsx\nimport { ChunkSuccessEventArgs, ChunkFailureEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction onChunkSuccess(args: ChunkSuccessEventArgs) {\n console.log(`Chunk ${args.chunkIndex + 1}/${args.totalChunk} sent for ${args.file.name}`);\n}\n\nfunction onChunkFailure(args: ChunkFailureEventArgs) {\n console.error(`Chunk ${args.chunkIndex} failed — retrying...`);\n}\n\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n chunkSuccess={onChunkSuccess}\n chunkFailure={onChunkFailure}\n/>\n```\n\n---\n\n## Common Patterns\n\n### Add custom form data to every upload\n```tsx\nfunction onUploading(args: UploadingEventArgs) {\n args.customFormData = [\n { folder: 'user-uploads' },\n { userId: '12345' },\n ];\n}\n```\n\n### Add a confirm dialog before file removal\n```tsx\nimport { DialogComponent } from '@syncfusion/ej2-react-popups';\n\nfunction onRemoving(args: RemovingEventArgs) {\n args.cancel = true; // always block immediate removal\n if (window.confirm(`Remove \"${args.filesData[0]?.name}\" from server?`)) {\n // Manually trigger removal after confirmation\n uploaderRef.current?.remove(args.filesData[0]);\n }\n}\n```\n\n### Cancel upload based on file content\n```tsx\nfunction onUploading(args: UploadingEventArgs) {\n const raw = args.fileData.rawFile as File;\n if (raw.size === 0) {\n args.cancel = true;\n console.warn('Empty file rejected:', args.fileData.name);\n }\n}\n```\n\n---\n\n## See Also\n\n- [Async upload](./async-upload.md) — `uploading` and `removing` event usage for headers\n- [Validation](./validation.md) — using `selected` and `uploading` for file filtering\n- [Sequential upload](./sequential-upload.md) — per-file event flow in sequential mode\n- [Chunk upload](./chunk-upload.md) — `chunkSuccess`, `chunkFailure` events\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10491,"content_sha256":"6ed5788d21653fee200d4917fbe2bf25c58ac397f6c66fe29dabba527d000e4f"},{"filename":"references/uploader-file-source.md","content":"# File Sources – Syncfusion React Uploader\n\n## Table of Contents\n- [Paste to Upload](#paste-to-upload)\n- [Directory Upload](#directory-upload)\n- [Drag and Drop](#drag-and-drop)\n- [Custom Drop Area](#custom-drop-area)\n- [Customize Drop Area Appearance](#customize-drop-area-appearance)\n- [Drop Effect](#drop-effect)\n- [Gotchas](#gotchas)\n\n---\n\n## Paste to Upload\n\nThe Uploader supports pasting images directly from the clipboard (Ctrl+V). The pasted image is saved on the server with the default filename `image.png`. Rename it server-side using a unique ID.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent, getUniqueID } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return (\n \u003cdiv>\n \u003cp>Press Ctrl+V to paste an image from clipboard\u003c/p>\n \u003cUploaderComponent asyncSettings={asyncSettings} />\n \u003c/div>\n );\n}\n```\n\n**Server-side: rename pasted file**\n\n```csharp\npublic void Save() {\n var httpPostedFile = System.Web.HttpContext.Current.Request.Files[\"UploadFiles\"];\n var fileSave = System.Web.HttpContext.Current.Server.MapPath(\"UploadedFiles\");\n var fileSavePath = Path.Combine(fileSave, httpPostedFile.FileName);\n\n if (!System.IO.File.Exists(fileSavePath)) {\n httpPostedFile.SaveAs(fileSavePath);\n var newName = System.Web.HttpContext.Current.Request.Form[\"fileName\"];\n var newPath = Path.Combine(fileSave, newName);\n System.IO.File.Move(fileSavePath, newPath);\n }\n}\n```\n\n> Use the `getUniqueID` utility from `@syncfusion/ej2-base` to generate unique filenames and avoid collisions.\n\n---\n\n## Directory Upload\n\nEnable `directoryUpload` to allow users to select an entire folder. All files and subdirectory files in the selected folder are uploaded.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n directoryUpload={true}\n />\n );\n}\n```\n\n> - Directory upload is supported only in browsers with HTML5 directory selection support.\n> - In Microsoft Edge, use **drag-and-drop** to upload directories (the browse button may not work).\n> - When `directoryUpload` is enabled, only folder selection is permitted — individual files cannot be browsed or dropped.\n\n**Server-side: preserve folder structure**\n\n```csharp\npublic void Save() {\n var httpPostedFile = HttpContext.Current.Request.Files[\"UploadFiles\"];\n var fileSave = HttpContext.Current.Server.MapPath(\"UploadedFiles\");\n // File name contains the relative path: \"folder/subfolder/file.txt\"\n string[] folders = httpPostedFile.FileName.Split('/');\n string fileSavePath;\n\n if (folders.Length > 1)\n {\n for (var i = 0; i \u003c folders.Length - 1; i++)\n {\n var newFolder = Path.Combine(fileSave, folders[i]);\n Directory.CreateDirectory(newFolder);\n fileSave = newFolder;\n }\n fileSavePath = Path.Combine(fileSave, folders[folders.Length - 1]);\n }\n else\n {\n fileSavePath = Path.Combine(fileSave, httpPostedFile.FileName);\n }\n\n if (!System.IO.File.Exists(fileSavePath))\n httpPostedFile.SaveAs(fileSavePath);\n}\n```\n\n---\n\n## Drag and Drop\n\nBy default, the Uploader component itself acts as the drop target. Users can drag files from the file system and drop them onto the uploader area, which highlights on hover.\n\n```tsx\n// Default drag-and-drop (no extra config needed)\n\u003cUploaderComponent asyncSettings={asyncSettings} />\n```\n\nThe drop area highlights with the `e-upload-drag-hover` CSS class when files are dragged over it.\n\n---\n\n## Custom Drop Area\n\nConfigure any external HTML element as the drop target using the `dropArea` property.\n\n```tsx\nimport React, { useRef, useEffect, useState } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const dropAreaRef = useRef\u003cHTMLDivElement>(null);\n const [dropAreaEl, setDropAreaEl] = useState\u003cHTMLElement | null>(null);\n\n // Set after DOM mounts\n useEffect(() => {\n setDropAreaEl(dropAreaRef.current);\n }, []);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return (\n \u003cdiv>\n \u003cdiv\n ref={dropAreaRef}\n id=\"customDropArea\"\n style={{\n border: '2px dashed #999',\n padding: '60px',\n textAlign: 'center',\n background: '#f9f9f9'\n }}\n >\n Drop files here or use the Browse button\n \u003c/div>\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n dropArea={dropAreaEl}\n />\n \u003c/div>\n );\n}\n```\n\n> `dropArea` accepts an `HTMLElement` reference or a CSS selector ID string (e.g., `'#customDropArea'`).\n\n**Using a string selector:**\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} dropArea=\"#customDropArea\" />\n```\n\n---\n\n## Customize Drop Area Appearance\n\nOverride the `.e-upload-drag-hover` CSS class to change the drop area style when files are dragged over it.\n\n```css\n/* Custom drag-hover style */\n.e-upload-drag-hover {\n border: 2px solid #007bff !important;\n background-color: #e8f0fe !important;\n}\n```\n\n**Hide the default drop area** by overriding these CSS classes:\n\n```css\n/* Hide the built-in Uploader container and file-select/drop area */\n.e-upload.e-control-wrapper {\n border: none !important;\n}\n\n.e-upload .e-file-select {\n display: none;\n}\n\n.e-upload .e-file-drop {\n display: none;\n}\n```\n\n---\n\n## Drop Effect\n\nControl the drag-and-drop cursor effect using the `dropEffect` property.\n\n| Value | Description |\n|---|---|\n| `'Default'` | Uses the browser default drag effect |\n| `'Copy'` | Shows a copy cursor |\n| `'Move'` | Shows a move cursor |\n| `'Link'` | Shows a link cursor |\n| `'None'` | Disables the drop effect visual |\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n dropEffect=\"Copy\"\n/>\n```\n\n---\n\n## Gotchas\n\n- **`directoryUpload` restricts to folders only** — Individual file browsing/dropping is disabled when enabled.\n- **Directory upload + Edge** — Use drag-and-drop in Edge; the browse button may not support folder selection.\n- **`dropArea` ref timing** — Pass the element after it mounts. Use `useEffect` + `useState` to avoid passing `null`.\n- **Paste upload filename** — Pasted images default to `image.png`; implement server-side renaming to avoid collisions.\n- **Drag-and-drop bypasses extension validation** — Add manual validation in the `selected` event for dropped files.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7004,"content_sha256":"75625e8ae0ee09cc1a46d3ce76ac69b87c9abeea1582e28306e17b35e7a741e7"},{"filename":"references/uploader-file-sources.md","content":"# File Sources\n\nThe Uploader supports multiple ways to select files: browse button, drag-and-drop, directory upload, paste from clipboard, and external button trigger.\n\n---\n\n## Drag and Drop\n\nDrag-and-drop is enabled by default. The component itself acts as the drop target. The drop area highlights when files are dragged over it (via `.e-upload-drag-hover`).\n\nNo configuration is needed for default drag-and-drop behavior.\n\n---\n\n## Custom Drop Area\n\nPoint drag-and-drop to an external element using the `dropArea` property. Set it in the `created` event after the component mounts:\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const dropRef = useRef\u003cHTMLDivElement>(null);\n\n const asyncSettings = {\n saveUrl: 'https://your-server/api/FileUploader/Save',\n removeUrl: 'https://your-server/api/FileUploader/Remove',\n };\n\n function onCreated() {\n if (uploaderRef.current && dropRef.current) {\n uploaderRef.current.dropArea = dropRef.current;\n uploaderRef.current.dataBind();\n }\n }\n\n return (\n \u003cdiv>\n \u003cdiv\n ref={dropRef}\n style={{ border: '2px dashed #999', padding: '40px', textAlign: 'center' }}\n >\n Drop files here or{' '}\n \u003ca href=\"#\" onClick={e => { e.preventDefault(); document.querySelector\u003cHTMLButtonElement>('.e-file-select-wrap button')?.click(); }}>\n Browse\n \u003c/a>\n \u003c/div>\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n autoUpload={false}\n created={onCreated}\n />\n \u003c/div>\n );\n}\n```\n\n**Hover style for custom drop area:**\n```css\n#dropArea.e-upload-drag-hover {\n background-color: #e0f0ff;\n border-color: #0078d4;\n}\n```\n\n---\n\n## Hiding the Default Drop Area\n\nTo suppress the built-in drop zone UI (e.g., when using a fully custom layout), hide it with CSS:\n\n```css\n.e-upload .e-file-drop {\n display: none;\n}\n```\n\nOr use the `cssClass` prop to scope the style to a specific instance:\n\n```tsx\n\u003cUploaderComponent cssClass=\"no-drop\" asyncSettings={asyncSettings} />\n```\n```css\n.no-drop .e-file-drop { display: none; }\n```\n\n---\n\n## Directory Upload\n\nUpload entire folders — all files and subdirectories — with `directoryUpload={true}`. The browser shows a folder picker instead of a file picker.\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} directoryUpload={true} />\n```\n\n> Directory upload requires a browser that supports the HTML5 directory capability. Edge supports it via drag-and-drop. The server receives each file with its relative path in the filename (slash-separated), enabling folder reconstruction.\n\n**Server-side: reconstruct folder structure**\n```csharp\npublic void Save()\n{\n var file = HttpContext.Current.Request.Files[\"UploadFiles\"];\n string[] folders = file.FileName.Split('/');\n var savePath = HttpContext.Current.Server.MapPath(\"UploadedFiles\");\n\n if (folders.Length > 1)\n {\n foreach (var folder in folders[..^1])\n {\n savePath = Path.Combine(savePath, folder);\n Directory.CreateDirectory(savePath);\n }\n }\n file.SaveAs(Path.Combine(savePath, folders[^1]));\n}\n```\n\n---\n\n## Paste-to-Upload (Clipboard Images)\n\nUsers can paste images from the clipboard (e.g., screenshots) directly into the uploader. The pasted image is received as `image.png` by default.\n\nRename the file server-side using `customFormData` to pass a unique filename:\n\n```tsx\nimport { getUniqueID } from '@syncfusion/ej2-base';\nimport { UploaderComponent, UploadingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://your-server/api/FileUploader/Save',\n removeUrl: 'https://your-server/api/FileUploader/Remove',\n };\n\n function onUploading(args: UploadingEventArgs) {\n if (args.fileData.fileSource === 'paste') {\n const baseName = args.fileData.name.replace(/\\.[^.]+$/, '');\n const uniqueName = getUniqueID(baseName) + '.png';\n args.customFormData = [{ fileName: uniqueName }];\n }\n }\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n uploading={onUploading}\n />\n );\n}\n```\n\n> Check `args.fileData.fileSource === 'paste'` in the `uploading` event to detect paste-sourced files.\n\n---\n\n## Trigger Browse from External Button\n\nProgrammatically open the file browser from any button outside the uploader:\n\n```tsx\nimport { select } from '@syncfusion/ej2-base';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function openBrowse(e: React.MouseEvent) {\n e.preventDefault();\n const browseBtn = select('.e-file-select-wrap button', document) as HTMLButtonElement;\n browseBtn?.click();\n }\n\n return (\n \u003cdiv>\n \u003cbutton onClick={openBrowse}>📎 Attach Files\u003c/button>\n \u003cUploaderComponent asyncSettings={asyncSettings} />\n \u003c/div>\n );\n}\n```\n\nIf multiple uploaders exist on the page, scope the selector to a specific container element.\n\n---\n\n## Sort Selected Files\n\nReorder files before upload using the `selected` event. Sort by name, size, or any custom criteria:\n\n```tsx\nimport { SelectedEventArgs, UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function onSelected(args: SelectedEventArgs) {\n // Sort alphabetically by filename\n args.filesData.sort((a, b) => a.name.localeCompare(b.name));\n args.modifiedFilesData = args.filesData;\n args.isModified = true;\n }\n\n return (\n \u003cUploaderComponent asyncSettings={asyncSettings} selected={onSelected} />\n );\n}\n```\n\n---\n\n## Get Total Size of Selected Files\n\nSum the sizes of all currently queued files:\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n function showTotalSize() {\n const files = uploaderRef.current?.getFilesData() ?? [];\n const totalBytes = files.reduce((sum, f) => sum + f.size, 0);\n const totalMB = (totalBytes / (1024 * 1024)).toFixed(2);\n alert(`Total: ${totalMB} MB across ${files.length} file(s)`);\n }\n\n return (\n \u003c>\n \u003cUploaderComponent ref={uploaderRef} asyncSettings={asyncSettings} autoUpload={false} />\n \u003cbutton onClick={showTotalSize}>Show Total Size\u003c/button>\n \u003c/>\n );\n}\n```\n\n---\n\n## See Also\n\n- [Validation](./validation.md) — filter files by type/size/MIME on selection or drop\n- [Getting started](./getting-started.md) — basic drop area setup\n- [Template customization](./template-customization.md) — invisible uploader pattern\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6673,"content_sha256":"3905234725fd92ca8b04d96f69e71af96ef4d052244e2dc42aa533c83ea604da"},{"filename":"references/uploader-getting-started.md","content":"# Getting Started – Syncfusion React Uploader\n\n## Table of Contents\n- [Dependencies](#dependencies)\n- [Installation](#installation)\n- [License Registration](#license-registration)\n- [CSS Theme Imports](#css-theme-imports)\n- [Basic Usage](#basic-usage)\n- [Drop Area Configuration](#drop-area-configuration)\n- [Success and Failure Handling](#success-and-failure-handling)\n- [React with Hooks (Functional Components)](#react-with-hooks-functional-components)\n- [React Class Component](#react-class-component)\n\n---\n\n## Dependencies\n\nThe React Uploader component requires the following packages:\n\n```\n@syncfusion/ej2-react-inputs\n └── @syncfusion/ej2-inputs\n ├── @syncfusion/ej2-base\n ├── @syncfusion/ej2-buttons\n ├── @syncfusion/ej2-popups\n └── @syncfusion/ej2-splitbuttons\n```\n\n---\n\n## Installation\n\nInstall the inputs package (includes UploaderComponent):\n\n```bash\nnpm install @syncfusion/ej2-react-inputs\n```\n\nOr install the full Syncfusion suite:\n\n```bash\nnpm install @syncfusion/ej2-react-inputs @syncfusion/ej2-base @syncfusion/ej2-buttons @syncfusion/ej2-popups\n```\n\n---\n\n## License Registration\n\nRegister your Syncfusion license key before rendering any component (typically in `main.tsx` or `index.tsx`):\n\n```tsx\nimport { registerLicense } from '@syncfusion/ej2-base';\nregisterLicense('YOUR_LICENSE_KEY');\n```\n\n> Get your free license key at [syncfusion.com/products/communitylicense](https://www.syncfusion.com/products/communitylicense).\n\n---\n\n## CSS Theme Imports\n\nImport required CSS files. The Uploader depends on base, buttons, inputs, and popups styles.\n\n**Material theme (recommended):**\n```tsx\nimport '@syncfusion/ej2-base/styles/material.css';\nimport '@syncfusion/ej2-buttons/styles/material.css';\nimport '@syncfusion/ej2-inputs/styles/material.css';\nimport '@syncfusion/ej2-popups/styles/material.css';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n```\n\n> Import order matters — follow the dependency sequence above.\n\n**Available themes:** `material`, `material3`, `bootstrap5`, `fluent`, `tailwind`, `highcontrast`\n\nReplace `material` with the desired theme name in all import paths.\n\n**Global stylesheet (styles.css / index.css):**\n```css\n@import \"../node_modules/@syncfusion/ej2-tailwind3-theme/styles/uploader/index.css\";\n```\n\n---\n\n## Basic Usage\n\nThe simplest uploader renders a browse button, a drop zone, and a file list. By default, `autoUpload` is `true`, so files upload immediately on selection.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-base/styles/material.css';\nimport '@syncfusion/ej2-buttons/styles/material.css';\nimport '@syncfusion/ej2-inputs/styles/material.css';\nimport '@syncfusion/ej2-popups/styles/material.css';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return \u003cUploaderComponent asyncSettings={asyncSettings} />;\n}\n\nexport default App;\n```\n\n**Disable auto upload** (show Upload/Clear buttons instead):\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n/>\n```\n\n> From v16.2.41+, Syncfusion EJ2 AJAX is used internally for server requests.\n\n---\n\n## Drop Area Configuration\n\nBy default, the Uploader acts as its own drop target. Configure an external element as the drop area using the `dropArea` property.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const dropAreaRef = useRef\u003cHTMLDivElement>(null);\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n return (\n \u003cdiv>\n \u003cdiv ref={dropAreaRef} style={{ border: '2px dashed #ccc', padding: '40px', textAlign: 'center' }}>\n Drop files here\n \u003c/div>\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n dropArea={dropAreaRef.current}\n />\n \u003c/div>\n );\n}\n```\n\n> `dropArea` accepts an `HTMLElement` reference or a CSS selector string.\n\n---\n\n## Success and Failure Handling\n\nHandle upload and remove operation results using `success` and `failure` events.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSuccess = (args: any): void => {\n // args.operation: 'upload' | 'remove'\n if (args.operation === 'upload') {\n console.log('File uploaded:', args.file.name);\n } else {\n console.log('File removed:', args.file.name);\n }\n };\n\n const onFailure = (args: any): void => {\n // args.operation: 'upload' | 'remove'\n console.error(`${args.operation} failed for:`, args.file.name);\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n success={onSuccess}\n failure={onFailure}\n />\n );\n}\n```\n\n---\n\n## React with Hooks (Functional Components)\n\nFull example using hooks with manual upload, ref access, and programmatic control:\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const handleUpload = () => {\n // Programmatically upload all queued files\n uploaderRef.current?.upload(uploaderRef.current.getFilesData());\n };\n\n const handleClear = () => {\n uploaderRef.current?.clearAll();\n };\n\n return (\n \u003cdiv>\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n autoUpload={false}\n />\n \u003cbutton onClick={handleUpload}>Upload\u003c/button>\n \u003cbutton onClick={handleClear}>Clear\u003c/button>\n \u003c/div>\n );\n}\n```\n\n---\n\n## React Class Component\n\n```tsx\nimport * as React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nclass App extends React.Component {\n public asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n public onSuccess(args: any): void {\n console.log('Operation:', args.operation, '| File:', args.file.name);\n }\n\n public render() {\n return (\n \u003cUploaderComponent\n asyncSettings={this.asyncSettings}\n autoUpload={false}\n success={this.onSuccess}\n />\n );\n }\n}\n\nexport default App;\n```\n\n---\n\n## Gotchas\n\n- **CSS import order** — Must match the dependency sequence; wrong order can break layout.\n- **License key** — Must be registered before any Syncfusion component renders.\n- **dropArea timing** — When using a `ref` for `dropArea`, pass the `.current` after the DOM has mounted (use `useEffect` or set it in component state).\n- **autoUpload default is `true`** — Files upload immediately. Set `autoUpload={false}` to show manual Upload/Clear buttons.\n- **AJAX library** — From v16.2.41+, the component uses EJ2 AJAX internally; use a Promise polyfill (e.g., `bluebird`) for IE support.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7697,"content_sha256":"6cb8243004ae185406233e1e9e88a39a79c449375a0982f84c24e4686d3ccb68"},{"filename":"references/uploader-integration-and-security.md","content":"# Integration and Security\n\nThis reference covers HTML form integration, JWT-secured uploads, localization of text content, and EJ1-to-EJ2 migration notes.\n\n---\n\n## HTML Form Integration\n\nThe Uploader works inside HTML forms like a standard `\u003cinput type=\"file\">`. When integrated with a form:\n\n- Set `saveUrl` and `removeUrl` to `null` (or omit `asyncSettings`)\n- Set `autoUpload={false}`\n- Add a `name` attribute to the input element\n\nWhen the form submits, selected files are sent as a collection to the form action.\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function onSubmit(e: React.FormEvent) {\n e.preventDefault();\n const form = e.target as HTMLFormElement;\n form.submit(); // Selected files are included in the form POST\n }\n\n return (\n \u003cform id=\"uploadForm\" method=\"post\" action=\"/submit\" onSubmit={onSubmit}>\n \u003cUploaderComponent\n id=\"fileUpload\"\n name=\"uploadedFiles\"\n autoUpload={false}\n allowedExtensions=\"image/*\"\n />\n \u003cbutton type=\"submit\">Submit Form\u003c/button>\n \u003c/form>\n );\n}\n```\n\n> Resetting the form (`form.reset()`) also clears the uploader's file list and all associated data.\n\n---\n\n## Form Integration with Syncfusion FormValidator\n\nUse Syncfusion's `FormValidator` to validate form fields including the file upload field:\n\n```tsx\nimport { select } from '@syncfusion/ej2-base';\nimport { FormValidator, FormValidatorModel } from '@syncfusion/ej2-inputs';\nimport { SelectedEventArgs, UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { useEffect, useRef } from 'react';\n\nfunction PhotoUploadForm() {\n const formRef = useRef\u003cHTMLFormElement>(null);\n let formValidator: FormValidator;\n\n useEffect(() => {\n const options: FormValidatorModel = {\n rules: {\n name: { required: [true, '* Name is required'] },\n email: { required: [true, '* Email is required'] },\n upload: { required: [true, '* Please select a file'] },\n },\n };\n formValidator = new FormValidator('#photoForm', options);\n }, []);\n\n function onFileSelected(args: SelectedEventArgs) {\n // Mirror the selected filename into the hidden text input for validation\n const input = document.getElementById('upload') as HTMLInputElement;\n if (input) input.value = args.filesData[0]?.name ?? '';\n }\n\n function onSubmit(e: React.FormEvent) {\n e.preventDefault();\n if (formValidator?.validate()) {\n formValidator.element.reset();\n alert('Form submitted successfully!');\n }\n }\n\n function openBrowse(e: React.MouseEvent) {\n e.preventDefault();\n (select('.e-file-select-wrap button', document) as HTMLButtonElement)?.click();\n }\n\n return (\n \u003cform id=\"photoForm\" method=\"post\" onSubmit={onSubmit}>\n \u003cdiv>\n \u003clabel>Name\u003c/label>\n \u003cinput type=\"text\" name=\"name\" id=\"name\" />\n \u003c/div>\n\n \u003cdiv>\n \u003clabel>Email\u003c/label>\n \u003cinput type=\"email\" name=\"email\" id=\"Email\" />\n \u003c/div>\n\n \u003cdiv>\n {/* Visible text input shows selected filename — used for FormValidator */}\n \u003cinput type=\"text\" readOnly id=\"upload\" name=\"upload\" />\n \u003cbutton type=\"button\" onClick={openBrowse}>Browse...\u003c/button>\n\n {/* Hidden uploader — no async, form mode */}\n \u003cUploaderComponent\n id=\"fileUpload\"\n autoUpload={false}\n allowedExtensions=\"image/*\"\n selected={onFileSelected}\n />\n \u003c/div>\n\n \u003cbutton type=\"submit\">Submit\u003c/button>\n \u003c/form>\n );\n}\n```\n\n**Key pattern:** A visible readonly `\u003cinput>` captures the selected filename for `FormValidator`. The actual `UploaderComponent` handles file selection. When the user picks a file, `onFileSelected` populates the text input, which then satisfies the `required` rule.\n\n---\n\n## JWT Authentication\n\nInject a JWT token into upload and remove requests using the `uploading` and `removing` events. The `currentRequest` property exposes the underlying `XMLHttpRequest`.\n\n**Client-side:**\n```tsx\nimport { UploaderComponent, UploadingEventArgs, RemovingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const token = 'your.jwt.token'; // In production: fetch from auth service\n\n const asyncSettings = {\n saveUrl: 'https://your-server/api/FileUploader/Save',\n removeUrl: 'https://your-server/api/FileUploader/Remove',\n };\n\n function onUploading(args: UploadingEventArgs) {\n (args.currentRequest as XMLHttpRequest)\n .setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n function onRemoving(args: RemovingEventArgs) {\n args.postRawFile = false; // Send filename only\n (args.currentRequest as XMLHttpRequest)\n .setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n uploading={onUploading}\n removing={onRemoving}\n />\n );\n}\n```\n\n> Replace the hardcoded token with a dynamic token from your auth context or a token refresh mechanism in production.\n\n**Server-side validation (ASP.NET Core):**\n```csharp\npublic async Task\u003cIActionResult> Save(IFormFile UploadFiles)\n{\n if (!IsAuthorized()) return Unauthorized();\n\n Directory.CreateDirectory(_uploads);\n var filePath = Path.Combine(_uploads, UploadFiles.FileName);\n var isChunk = UploadFiles.ContentType == \"application/octet-stream\";\n using var stream = new FileStream(filePath, isChunk ? FileMode.Append : FileMode.Create);\n await UploadFiles.CopyToAsync(stream);\n return Ok();\n}\n\nprivate bool IsAuthorized()\n{\n var header = Request.Headers[\"Authorization\"].ToString();\n if (!header.StartsWith(\"Bearer \")) return false;\n var token = header[\"Bearer \".Length..];\n return ValidateToken(token); // Replace with real JWT validation\n}\n\npublic IActionResult Remove(string UploadFiles)\n{\n if (!IsAuthorized()) return Unauthorized();\n var path = Path.Combine(_uploads, UploadFiles);\n if (System.IO.File.Exists(path)) System.IO.File.Delete(path);\n return Ok();\n}\n```\n\n---\n\n## Localization\n\nCustomize all static text in the Uploader — button labels, status messages, tooltips, and drop area text — using Syncfusion's `L10n` (localization) service.\n\n**Available text keys:**\n\n| Key | Default (en-US) | Description |\n|-----|-----------------|-------------|\n| `Browse` | Browse | Browse button label |\n| `Clear` | Clear | Clear button label |\n| `Upload` | Upload | Upload button label |\n| `dropFilesHint` | or Drop files here | Drop area text |\n| `uploadSuccessMessage` | File uploaded successfully | Success status |\n| `uploadFailedMessage` | File failed to upload | Failure status |\n| `removedSuccessMessage` | File removed successfully | Remove success |\n| `removedFailedMessage` | File failed to remove | Remove failure |\n| `inProgress` | Uploading | In-progress status |\n| `readyToUploadMessage` | Ready to upload | File selected state |\n| `invalidMaxFileSize` | File size is too large | Size validation error |\n| `invalidMinFileSize` | File size is too small | Min size error |\n| `invalidFileType` | File type is not allowed | Extension error |\n| `remove` | Remove | Remove icon tooltip |\n| `cancel` | Cancel | Cancel icon tooltip |\n| `delete` | Delete file | Delete icon tooltip |\n| `pauseUpload` | File upload paused | Chunk pause status |\n| `fileUploadCancel` | File upload cancelled | Cancel status |\n\n**Example — French (fr-CH) localization:**\n\n```tsx\nimport { L10n } from '@syncfusion/ej2-base';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { useEffect } from 'react';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://your-server/api/FileUploader/Save',\n removeUrl: 'https://your-server/api/FileUploader/Remove',\n };\n\n useEffect(() => {\n L10n.load({\n 'fr-CH': {\n uploader: {\n Browse: 'Feuilleter',\n Clear: 'Clair',\n Upload: 'Télécharger',\n cancel: 'Annuler',\n delete: 'Supprimer le fichier',\n totalFiles: 'Total des fichiers',\n size: 'taille',\n dropFilesHint: 'ou Déposer des fichiers ici',\n inProgress: 'Téléchargement',\n invalidFileType: 'Le type de fichier n\\'est pas autorisé',\n invalidMaxFileSize: 'La taille du fichier dépasse 28 Mo',\n readyToUploadMessage: 'Prêt à télécharger',\n remove: 'Retirer',\n removedSuccessMessage: 'Fichier supprimé avec succès',\n uploadFailedMessage: 'Impossible d\\'importer le fichier',\n uploadSuccessMessage: 'Fichier téléchargé avec succès',\n },\n },\n });\n }, []);\n\n return \u003cUploaderComponent asyncSettings={asyncSettings} locale=\"fr-CH\" />;\n}\n```\n\n> Load locale strings before the component renders (in `useEffect` with `[]` or outside the component). The `locale` prop on `UploaderComponent` activates the loaded locale.\n\n**Combining localization with RTL:**\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n locale=\"ar\"\n enableRtl={true}\n/>\n```\n\n---\n\n## EJ1 to EJ2 Migration\n\nKey differences between EJ1 (`ej.Uploader`) and EJ2 (`UploaderComponent`):\n\n| Feature | EJ1 | EJ2 |\n|---------|-----|-----|\n| Package | `@syncfusion/ej2` (monolith) | `@syncfusion/ej2-react-inputs` |\n| Component | `ej.Uploader` | `UploaderComponent` |\n| Async config | `saveUrl`, `removeUrl` as direct props | `asyncSettings={{ saveUrl, removeUrl }}` |\n| Auto upload | `autoUpload` prop | `autoUpload` prop (same) |\n| Events | jQuery-style callbacks | React event props (`success`, `failure`, etc.) |\n| File list access | `getFilesData()` | `getFilesData()` (same) |\n| Template | String-based HTML template | JSX function or HTML string |\n\n---\n\n## See Also\n\n- [Async upload](./async-upload.md) — `uploading` event and custom headers\n- [Events](./events.md) — full event reference for `removing`, `uploading`\n- [Style & accessibility](./style-accessibility.md) — RTL support, theme imports\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9914,"content_sha256":"c7a1ef07847fc88d025f44eb1a7801e119fcce9e256e1bea5b647807ef62cac5"},{"filename":"references/uploader-sequential-upload.md","content":"# Sequential Upload\n\nBy default, the Uploader sends all selected files to the server simultaneously (parallel). Sequential upload changes this so files are processed **one at a time** — the next file only starts after the current one completes (success or failure). This reduces server load and upload failures when handling many or large files.\n\n---\n\n## When to Use Sequential Upload\n\n| Use parallel (default) | Use sequential |\n|------------------------|----------------|\n| Few small files | Many files or large files |\n| Server handles concurrent requests well | Server has concurrency limits |\n| Upload speed is priority | Upload stability is priority |\n| — | Need per-file status logs |\n\n---\n\n## Enabling Sequential Upload\n\nSet `sequentialUpload={true}` on the component. No other configuration is required.\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://your-server/api/FileUploader/Save',\n removeUrl: 'https://your-server/api/FileUploader/Remove',\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n />\n );\n}\n```\n\nFiles are queued in the order they were selected or dropped. The first file uploads immediately; each subsequent file waits for the previous to finish.\n\n---\n\n## Sequential Upload with Manual Trigger\n\nCombine `sequentialUpload` with `autoUpload={false}` to let the user review files before starting the sequential process:\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n autoUpload={false}\n/>\n```\n\nThe Upload button triggers sequential processing. Files are still sent one at a time after the user clicks Upload.\n\n---\n\n## Per-File Progress Tracking\n\nIn sequential mode, each file fires its own `progress`, `success`, and `failure` events — making per-file status displays straightforward:\n\n```tsx\nimport { UploaderComponent, ProgressEventArgs, SuccessEventArgs, FailureEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\ninterface FileStatus {\n name: string;\n status: 'uploading' | 'success' | 'failed';\n percent?: number;\n}\n\nfunction App() {\n const [fileLog, setFileLog] = useState\u003cFileStatus[]>([]);\n\n function onProgress(args: ProgressEventArgs) {\n const percent = Math.round((args.e.loaded / args.e.total) * 100);\n setFileLog(prev => {\n const exists = prev.find(f => f.name === args.file.name);\n if (exists) return prev.map(f => f.name === args.file.name ? { ...f, percent } : f);\n return [...prev, { name: args.file.name, status: 'uploading', percent }];\n });\n }\n\n function onSuccess(args: SuccessEventArgs) {\n if (args.operation === 'upload') {\n setFileLog(prev =>\n prev.map(f => f.name === args.file?.name ? { ...f, status: 'success' } : f)\n );\n }\n }\n\n function onFailure(args: FailureEventArgs) {\n setFileLog(prev =>\n prev.map(f => f.name === args.file?.name ? { ...f, status: 'failed' } : f)\n );\n }\n\n return (\n \u003c>\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n progress={onProgress}\n success={onSuccess}\n failure={onFailure}\n />\n \u003cul>\n {fileLog.map(f => (\n \u003cli key={f.name}>{f.name} — {f.status} {f.percent !== undefined ? `(${f.percent}%)` : ''}\u003c/li>\n ))}\n \u003c/ul>\n \u003c/>\n );\n}\n```\n\n---\n\n## Custom HTTP Headers Per File\n\nThe `uploading` event fires separately for each file in sequential mode, so headers can be set or customized per file:\n\n```tsx\nimport { UploaderComponent, UploadingEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function onUploading(args: UploadingEventArgs) {\n (args.currentRequest as XMLHttpRequest).setRequestHeader('Authorization', `Bearer ${getToken()}`);\n // Can also use per-file metadata if needed\n (args.currentRequest as XMLHttpRequest).setRequestHeader('X-File-Name', args.fileData.name);\n }\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n uploading={onUploading}\n />\n );\n}\n```\n\n---\n\n## actionComplete: After All Files Finish\n\nThe `actionComplete` event fires once after **all files** in the sequential queue have been processed. Use this for final notifications, redirects, or summary views:\n\n```tsx\nimport { UploaderComponent, ActionCompleteEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function onActionComplete(args: ActionCompleteEventArgs) {\n const succeeded = args.fileData.filter(f => f.status === 'File uploaded successfully');\n const failed = args.fileData.filter(f => f.statusCode === '0');\n console.log(`Done: ${succeeded.length} succeeded, ${failed.length} failed`);\n }\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n sequentialUpload={true}\n actionComplete={onActionComplete}\n />\n );\n}\n```\n\n---\n\n## Dynamically Toggling Sequential Upload\n\nToggle sequential mode at runtime (e.g., via a user preference) using a ref and `dataBind()`:\n\n```tsx\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useState } from 'react';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const [isSequential, setIsSequential] = useState(false);\n\n function toggleMode() {\n const next = !isSequential;\n setIsSequential(next);\n if (uploaderRef.current) {\n uploaderRef.current.sequentialUpload = next;\n uploaderRef.current.dataBind();\n }\n }\n\n return (\n \u003c>\n \u003cbutton onClick={toggleMode}>\n Mode: {isSequential ? 'Sequential' : 'Parallel'}\n \u003c/button>\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n sequentialUpload={isSequential}\n />\n \u003c/>\n );\n}\n```\n\n> Always call `dataBind()` after updating a property programmatically to ensure the component reflects the new value.\n\n---\n\n## Key Events in Sequential Mode\n\n| Event | When it fires |\n|-------|---------------|\n| `uploading` | Before each individual file is sent |\n| `progress` | During upload of each file |\n| `success` | After each file successfully uploads |\n| `failure` | If a file fails — next file starts automatically |\n| `actionComplete` | After all files in queue are processed |\n\n> A failed file remains in the list with error status and can be retried using the component's `retry` method. Failure does not stop the queue.\n\n---\n\n## See Also\n\n- [Async upload](./async-upload.md) — save/remove config, auto/manual upload\n- [Chunk upload](./chunk-upload.md) — large file uploads with pause/resume\n- [Events](./events.md) — full event reference\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6697,"content_sha256":"d0718f3c2d99ab4b11191b773ba66e5b6f93137bbfe8644e30501320bab0f05a"},{"filename":"references/uploader-style-accessibility.md","content":"# Style and Accessibility\n\nThis reference covers CSS customization of the Uploader component's appearance and its accessibility features (WCAG 2.2, keyboard navigation, screen reader support, RTL).\n\n---\n\n## CSS Selectors Reference\n\n| Selector | Targets |\n|----------|---------|\n| `.e-upload.e-control-wrapper` | Overall component wrapper |\n| `.e-upload .e-file-select-wrap .e-btn` | Browse button |\n| `.e-upload .e-upload-actions .e-btn` | Upload / Clear action buttons |\n| `.e-upload .e-file-select-wrap .e-file-drop` | Drop area text |\n| `.e-upload .e-upload-files .e-upload-file-list` | Individual file list items |\n| `.e-upload .e-upload-progress-bar .e-upload-progress` | Progress bar fill |\n| `.e-upload .e-file-status` | File status text |\n| `.e-upload-drag-hover` | Drop area state when file is dragged over it |\n\n---\n\n## Customizing Wrapper Dimensions\n\n```css\n.e-upload.e-control-wrapper,\n.e-bigger.e-small .e-upload.e-control-wrapper {\n height: 300px;\n width: 400px;\n}\n```\n\n---\n\n## Customizing Buttons\n\nStyle the Browse, Upload, and Clear buttons:\n\n```css\n.e-upload .e-file-select-wrap .e-btn,\n.e-upload .e-upload-actions .e-btn,\n.e-bigger.e-small .e-upload .e-file-select-wrap .e-btn,\n.e-bigger.e-small .e-upload .e-upload-actions .e-btn {\n background-color: #0078d4;\n color: #fff;\n border-radius: 4px;\n font-family: 'Segoe UI', sans-serif;\n height: 36px;\n}\n```\n\n---\n\n## Customizing the Drop Area Text\n\n```css\n.e-upload .e-file-select-wrap .e-file-drop,\n.e-bigger.e-small .e-upload .e-file-select-wrap .e-file-drop {\n font-size: 16px;\n color: #555;\n}\n```\n\n---\n\n## Customizing the File List\n\n```css\n/* File list item background */\n.e-upload .e-upload-files .e-upload-file-list {\n background-color: #f9f9f9;\n border-radius: 4px;\n margin-bottom: 4px;\n}\n```\n\n---\n\n## Customizing the Progress Bar\n\n```css\n/* Progress bar fill color */\n.e-upload .e-upload-progress-bar .e-upload-progress {\n background-color: #28a745;\n}\n\n/* Thicker progress bar */\n.e-upload .e-upload-progress-bar {\n height: 6px;\n border-radius: 3px;\n}\n```\n\n---\n\n## Theme Integration\n\nApply a Syncfusion theme by importing the correct CSS files. All three imports must use the same theme name:\n\n```css\n/* Tailwind3 */\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css\";\n\n/* Bootstrap 5.3 */\n@import \"../node_modules/@syncfusion/ej2-base/styles/bootstrap5.3.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/bootstrap5.3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/bootstrap5.3.css\";\n\n/* Material 3 */\n@import \"../node_modules/@syncfusion/ej2-base/styles/material3.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/material3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/material3.css\";\n\n/* Fluent 2 */\n@import \"../node_modules/@syncfusion/ej2-base/styles/fluent2.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/fluent2.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/fluent2.css\";\n```\n\n---\n\n## Accessibility Standards\n\nThe Syncfusion React Uploader fully meets:\n\n| Standard | Status |\n|----------|--------|\n| WCAG 2.2 | ✅ Full compliance |\n| Section 508 | ✅ Full compliance |\n| ADA | ✅ Full compliance |\n| Screen reader support | ✅ Full |\n| RTL support | ✅ Full |\n| Color contrast | ✅ Full |\n| Mobile device support | ✅ Full |\n| Keyboard navigation | ✅ Full |\n| Axe-core validation | ✅ Passes |\n| Accessibility checker | ✅ Passes |\n\n---\n\n## Keyboard Navigation\n\n| Key | Action |\n|-----|--------|\n| `Tab` | Move focus to the next interactive element |\n| `Shift + Tab` | Move focus to the previous element |\n| `Enter` | Activate the focused button (Browse, Upload, Clear, Remove) |\n| `Esc` | Close the file browser dialog; cancel pending upload |\n\nThe component is fully keyboard-operable without a mouse. Users can browse, upload, and remove files entirely from the keyboard.\n\n---\n\n## ARIA Attributes\n\nThe Uploader sets appropriate ARIA attributes automatically:\n- Browse button: `role=\"button\"` with descriptive `aria-label`\n- Progress bar: `role=\"progressbar\"` with `aria-valuenow`, `aria-valuemin`, `aria-valuemax`\n- File list: `role=\"list\"` with `role=\"listitem\"` per file\n\nNo additional ARIA configuration is required for standard use.\n\n---\n\n## RTL (Right-to-Left) Support\n\nEnable RTL layout with the `enableRtl` prop:\n\n```tsx\n\u003cUploaderComponent asyncSettings={asyncSettings} enableRtl={true} />\n```\n\nThe entire UI layout mirrors for RTL locales. Pair with localization for a complete RTL experience.\n\n---\n\n## See Also\n\n- [Integration & security](./integration-and-security.md) — localization, form support, JWT\n- [Template customization](./template-customization.md) — custom file list UI\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4872,"content_sha256":"192ac19b2377aa82aca7019b760c76d5f1e0443dbe8ecdf9c85f1226cdbd5f6b"},{"filename":"references/uploader-template-customization.md","content":"# Template and Customization – Syncfusion React Uploader\n\n## Table of Contents\n- [File List Template](#file-list-template)\n- [Custom Upload UI (showFileList)](#custom-upload-ui-showfilelist)\n- [Custom Buttons](#custom-buttons)\n- [CSS Class](#css-class)\n- [Style and Appearance](#style-and-appearance)\n- [Customize Progress Bar](#customize-progress-bar)\n- [Hide Default Drop Area](#hide-default-drop-area)\n- [fileListRendering Event](#filelistrendering-event)\n- [Gotchas](#gotchas)\n\n---\n\n## File List Template\n\nUse the `template` property to customize how each file is rendered in the file list. Provide an HTML string or a function returning HTML.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n // Template as a function returning JSX\n const fileListTemplate = () => {\n return (\n \u003cdiv className=\"custom-file-item\">\n \u003cspan className=\"file-icon e-icons e-file-document\">\u003c/span>\n \u003cdiv className=\"file-info\">\n \u003cspan className=\"file-name\">${name}\u003c/span>\n \u003cspan className=\"file-size\">${size} bytes\u003c/span>\n \u003c/div>\n \u003c/div>\n );\n }\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n template={fileListTemplate}\n />\n );\n}\n```\n\n> When a `template` is used, remove and progress bar actions are handled through `removing` and `progress` events — the default icons are replaced by your template.\n\n---\n\n## Custom Upload UI (showFileList)\n\nBuild a fully custom file list UI by hiding the default list with `showFileList={false}` and rendering your own.\n\nWhen using `showFileList={false}`, pass `true` as the second argument to `upload()` and `remove()` to indicate a custom UI:\n\n```tsx\n// upload(filesData, customUI=true)\nuploaderRef.current?.upload(filesData, true);\n\n// remove(filesData, customUI=true)\nuploaderRef.current?.remove(filesData, true);\n```\n\n**Full example — custom file list with progress tracking:**\n\n```tsx\nimport React, { useRef, useState } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n const [fileList, setFileList] = useState\u003cany[]>([]);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n setFileList(prev => [...prev, ...args.filesData]);\n };\n\n const onProgress = (args: any): void => {\n const progress = Math.round((args.e.loaded / args.e.total) * 100);\n setFileList(prev =>\n prev.map(f => f.name === args.file.name ? { ...f, progress } : f)\n );\n };\n\n const onSuccess = (args: any): void => {\n if (args.operation === 'upload') {\n setFileList(prev =>\n prev.map(f => f.name === args.file.name ? { ...f, status: 'done' } : f)\n );\n }\n };\n\n const handleUpload = (file: any): void => {\n uploaderRef.current?.upload([file], true);\n };\n\n const handleRemove = (file: any): void => {\n uploaderRef.current?.remove([file], true);\n setFileList(prev => prev.filter(f => f.name !== file.name));\n };\n\n return (\n \u003cdiv>\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n showFileList={false}\n autoUpload={false}\n selected={onSelected}\n progress={onProgress}\n success={onSuccess}\n />\n \u003cul>\n {fileList.map(file => (\n \u003cli key={file.name}>\n \u003cspan>{file.name}\u003c/span>\n {file.progress !== undefined && \u003cspan> — {file.progress}%\u003c/span>}\n {file.status === 'done' && \u003cspan> ✓ Uploaded\u003c/span>}\n \u003cbutton onClick={() => handleUpload(file)}>Upload\u003c/button>\n \u003cbutton onClick={() => handleRemove(file)}>Remove\u003c/button>\n \u003c/li>\n ))}\n \u003c/ul>\n \u003c/div>\n );\n}\n```\n\n---\n\n## Custom Buttons\n\nCustomize the Browse, Clear, and Upload button labels using the `buttons` property. Accepts plain text strings or HTML element strings.\n\n```tsx\n// Text labels\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n buttons={{\n browse: 'Choose File',\n clear: 'Clear All',\n upload: 'Upload All'\n }}\n/>\n```\n\n**HTML element buttons:**\n\n```tsx\nconst customButtons = {\n browse: '\u003cspan class=\"e-icons e-browse\"> Browse Files\u003c/span>',\n clear: '\u003cspan class=\"e-icons e-clear\"> Clear\u003c/span>',\n upload: '\u003cspan class=\"e-icons e-upload\"> Upload\u003c/span>'\n};\n\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n buttons={customButtons}\n/>\n```\n\n> The `buttons` property takes precedence over locale strings. If both are configured, `buttons` wins.\n\n---\n\n## CSS Class\n\nAdd custom CSS classes to the Uploader root element using `cssClass`.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n cssClass=\"my-custom-uploader dark-theme\"\n/>\n```\n\n```css\n.my-custom-uploader {\n border: 2px solid #007bff;\n border-radius: 8px;\n}\n```\n\n---\n\n## Style and Appearance\n\nOverride Syncfusion CSS classes to customize the uploader's visual appearance.\n\n### Uploader Wrapper Dimensions\n\n```css\n.e-upload.e-control-wrapper,\n.e-bigger.e-small .e-upload.e-control-wrapper {\n height: 300px;\n width: 400px;\n}\n```\n\n### Browse Button Style\n\n```css\n.e-upload .e-file-select-wrap .e-btn,\n.e-upload .e-upload-actions .e-btn,\n.e-bigger.e-small .e-upload .e-file-select-wrap .e-btn,\n.e-bigger.e-small .e-upload .e-upload-actions .e-btn {\n font-family: cursive;\n height: 40px;\n background-color: #4CAF50;\n color: white;\n}\n```\n\n### Drop Area Text Style\n\n```css\n.e-upload .e-file-select-wrap .e-file-drop,\n.e-bigger.e-small .e-upload .e-file-select-wrap .e-file-drop {\n font-size: 18px;\n color: #555;\n}\n```\n\n### File List Container Style\n\n```css\n.e-upload .e-upload-files .e-upload-file-list {\n background-color: #f0f4f8;\n}\n```\n\n---\n\n## Customize Progress Bar\n\nOverride the progress bar's color and height by targeting the Syncfusion progress bar classes.\n\n```css\n/* Progress bar track (background) */\n.e-upload .e-upload-files .e-file-progress-wrap {\n background-color: #e0e0e0;\n border-radius: 4px;\n height: 6px;\n}\n\n/* Progress bar fill */\n.e-upload .e-upload-files .e-file-progress-wrap .e-upload-progress-line {\n background-color: #007bff;\n height: 6px;\n}\n```\n\n---\n\n## Hide Default Drop Area\n\nHide the default drop area while keeping the Uploader functional for programmatic or custom use.\n\n```css\n.e-upload.e-control-wrapper {\n border: none !important;\n}\n\n.e-upload .e-file-select {\n display: none;\n}\n\n.e-upload .e-file-drop {\n display: none;\n}\n```\n\n> This is useful when implementing a completely custom file selection UI using an external button to trigger the file browser.\n\n---\n\n## fileListRendering Event\n\nThe `fileListRendering` event fires before each file item is rendered in the list. Use it to customize individual file item elements.\n\n```tsx\nconst onFileListRendering = (args: any): void => {\n // args.element — the LI element being rendered\n // args.fileInfo — file data for this item\n if (args.fileInfo.size > 1000000) {\n args.element.style.backgroundColor = '#fff3cd'; // Highlight large files\n }\n};\n\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n fileListRendering={onFileListRendering}\n/>\n```\n\n> The deprecated `rendering` event is replaced by `fileListRendering`. Use `fileListRendering` in new implementations.\n\n---\n\n## Gotchas\n\n- **Template + remove/progress** — When using a `template`, the default remove icon and progress bar are replaced. Hook into `removing` and `progress` events to implement these in your template.\n- **`showFileList={false}` + upload/remove** — Always pass `true` as the second argument (`custom`) when calling `upload()` and `remove()` with a custom UI.\n- **`buttons` overrides locale** — If both `buttons` and `locale` are set, `buttons` property values take precedence.\n- **`cssClass` appends** — `cssClass` adds to the existing root class, not replaces it.\n- **CSS specificity** — Syncfusion styles have high specificity; use `!important` or add a more specific selector when overriding.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8383,"content_sha256":"b99bac37da96e135f13e1de7bf98bcfd33d22183c2ec5efd8845ea4794867de1"},{"filename":"references/uploader-validation.md","content":"# Validation – Syncfusion React Uploader\n\n## Table of Contents\n- [Overview](#overview)\n- [File Type Validation](#file-type-validation)\n- [File Size Validation](#file-size-validation)\n- [Maximum Files Count](#maximum-files-count)\n- [Duplicate File Prevention](#duplicate-file-prevention)\n- [Drag-and-Drop Image Validation](#drag-and-drop-image-validation)\n- [Required Field Validation](#required-field-validation)\n- [Gotchas](#gotchas)\n\n---\n\n## Overview\n\nThe Uploader validates files by extension and size using built-in properties. Custom logic for max file count, duplicates, and drag-and-drop validation is handled via the `selected` event. Validation runs during both file selection (browse button) and drag-and-drop operations.\n\n---\n\n## File Type Validation\n\nUse `allowedExtensions` to restrict accepted file formats. Specify a comma-separated list of extensions (with leading dots).\n\n```tsx\n// Allow only PDF and Word documents\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n allowedExtensions=\".pdf,.doc,.docx\"\n/>\n\n// Allow only images\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n allowedExtensions=\".jpg,.jpeg,.png,.gif,.bmp\"\n/>\n```\n\n> **Drag-and-drop limitation** — `allowedExtensions` filters files in the browse dialog but does **not** automatically filter drag-and-drop files. Use the `selected` event to manually validate dropped files (see [Drag-and-Drop Image Validation](#drag-and-drop-image-validation)).\n\nYou can also set the HTML `accept` attribute via `htmlAttributes`:\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n htmlAttributes={{ accept: '.pdf,.docx' }}\n/>\n```\n\n---\n\n## File Size Validation\n\nSet `minFileSize` and `maxFileSize` (in bytes) to reject files outside the acceptable size range.\n\n| Property | Default | Description |\n|---|---|---|\n| `minFileSize` | `0` | Minimum allowed size in bytes |\n| `maxFileSize` | `30000000` (~28.6 MB) | Maximum allowed size in bytes |\n\n```tsx\n// Allow only files between 1 KB and 5 MB\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n minFileSize={1024}\n maxFileSize={5242880}\n/>\n```\n\n**Convert bytes to human-readable format** using `bytesToSize`:\n\n```tsx\nimport { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n const onUploading = (args: any): void => {\n // Convert file size to KB/MB string\n const sizeStr = uploaderRef.current?.bytesToSize(args.fileData.size);\n console.log('File size:', sizeStr);\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n uploading={onUploading}\n />\n );\n}\n```\n\n---\n\n## Maximum Files Count\n\nLimit the number of files in the upload queue using the `selected` event. Access current files with `getFilesData()` and modify `eventArgs.modifiedFilesData` to filter selections.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nconst MAX_FILES = 5;\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n const existingFiles = uploaderRef.current?.getFilesData() ?? [];\n const totalCount = existingFiles.length + args.filesData.length;\n\n if (totalCount > MAX_FILES) {\n // Keep only up to MAX_FILES\n const allowed = MAX_FILES - existingFiles.length;\n args.modifiedFilesData = args.filesData.slice(0, allowed);\n console.warn(`Max ${MAX_FILES} files allowed. Extra files removed.`);\n }\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n selected={onSelected}\n />\n );\n}\n```\n\n---\n\n## Duplicate File Prevention\n\nPrevent the same file from being added twice by comparing names in the `selected` event.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n const uploaderRef = useRef\u003cUploaderComponent>(null);\n\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n const existingFiles = uploaderRef.current?.getFilesData() ?? [];\n const existingNames = new Set(existingFiles.map((f: any) => f.name));\n\n // Remove duplicates from new selection\n args.modifiedFilesData = args.filesData.filter(\n (file: any) => !existingNames.has(file.name)\n );\n\n if (args.modifiedFilesData.length \u003c args.filesData.length) {\n console.warn('Duplicate files removed from selection.');\n }\n };\n\n return (\n \u003cUploaderComponent\n ref={uploaderRef}\n asyncSettings={asyncSettings}\n selected={onSelected}\n />\n );\n}\n```\n\n---\n\n## Drag-and-Drop Image Validation\n\nBy default, `allowedExtensions` is not enforced during drag-and-drop. Validate dropped files manually in the `selected` event.\n\n```tsx\nimport React from 'react';\nimport { UploaderComponent } from '@syncfusion/ej2-react-inputs';\n\nconst ALLOWED_IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/tiff'];\n\nfunction App() {\n const asyncSettings = {\n saveUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Save',\n removeUrl: 'https://services.syncfusion.com/react/production/api/FileUploader/Remove'\n };\n\n const onSelected = (args: any): void => {\n // Filter to images only (for drag-and-drop scenarios)\n args.modifiedFilesData = args.filesData.filter((file: any) =>\n ALLOWED_IMAGE_TYPES.includes(file.rawFile.type)\n );\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n allowedExtensions=\".jpg,.jpeg,.png,.gif,.bmp,.tiff\"\n selected={onSelected}\n />\n );\n}\n```\n\n> Setting `allowedExtensions=\"image/*\"` restricts the browse dialog to images, but drag-and-drop still needs the `selected` event filter.\n\n---\n\n## Required Field Validation\n\nApply the `required` attribute via `htmlAttributes` to enforce that the uploader has files before form submission. Use `data-required-message` for a custom validation message.\n\n```tsx\n\u003cUploaderComponent\n asyncSettings={asyncSettings}\n htmlAttributes={{\n required: 'required',\n 'data-required-message': 'Please select at least one file'\n }}\n/>\n```\n\n---\n\n## Gotchas\n\n- **Drag-and-drop bypasses `allowedExtensions`** — Always add manual validation in `selected` for dropped files.\n- **`minFileSize` default is 0** — Empty files (0 bytes) are allowed by default unless you set `minFileSize > 0`.\n- **`maxFileSize` default is ~28.6 MB** (30,000,000 bytes) — Override if your server has a different limit.\n- **`modifiedFilesData` must be set** — In the `selected` event, setting `args.modifiedFilesData` replaces the file queue; not setting it leaves all files in.\n- **`getFilesData()` returns current queue** — Use it to count existing files before adding new ones.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7205,"content_sha256":"708b0c2a07ff58116ff8718f4023af5ba0a0ee186d0d86295fccec230ff0bb86"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Implementing Syncfusion React Inputs","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Uploader","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ","type":"text"},{"text":"UploaderComponent","type":"text","marks":[{"type":"strong"}]},{"text":" provides a rich file upload control with async upload, drag-and-drop, chunk upload with pause/resume/cancel, validation, templates, form integration, and accessibility support.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Agentic use:","type":"text","marks":[{"type":"strong"}]},{"text":" Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation).","type":"text"}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installing ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"text":" 🛑 ","type":"text"},{"text":"STOP — Do not install packages autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm install @syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":". Verify with ","type":"text","marks":[{"type":"em"}]},{"text":"npm audit","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"License registration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Basic ","type":"text"},{"text":"UploaderComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" usage in JSX/TSX","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drop area configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Success and failure event handling","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Asynchronous Upload","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/async-upload.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-async-upload.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"asyncSettings","type":"text","marks":[{"type":"code_inline"}]},{"text":" with ","type":"text"},{"text":"saveUrl","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"removeUrl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multiple vs. single file upload (","type":"text"},{"text":"multiple","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Auto upload vs. manual upload (","type":"text"},{"text":"autoUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Sequential upload (","type":"text"},{"text":"sequentialUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preloaded files (","type":"text"},{"text":"files","type":"text","marks":[{"type":"code_inline"}]},{"text":" property)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adding custom HTTP headers via ","type":"text"},{"text":"uploading","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"removing","type":"text","marks":[{"type":"code_inline"}]},{"text":" events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Server-side save/remove action examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Chunk Upload","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/chunk-upload.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-chunk-upload.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling chunk upload with ","type":"text"},{"text":"asyncSettings.chunkSize","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Retry configuration (","type":"text"},{"text":"retryCount","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"retryAfterDelay","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pause and resume chunked uploads (","type":"text"},{"text":"pause","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"resume","type":"text","marks":[{"type":"code_inline"}]},{"text":" methods)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cancel uploads (","type":"text"},{"text":"cancel","type":"text","marks":[{"type":"code_inline"}]},{"text":" method)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"chunkSuccess","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"chunkFailure","type":"text","marks":[{"type":"code_inline"}]},{"text":" events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Server-side chunk handling (C#)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/validation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-validation.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Allowed file extensions (","type":"text"},{"text":"allowedExtensions","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"File size limits (","type":"text"},{"text":"minFileSize","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"maxFileSize","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Maximum file count using ","type":"text"},{"text":"selected","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Duplicate file prevention","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drag-and-drop image validation","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"File Sources","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/file-source.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-file-source.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clipboard paste upload","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Directory/folder upload (","type":"text"},{"text":"directoryUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drag-and-drop with custom drop area (","type":"text"},{"text":"dropArea","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customizing drop area appearance","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Templates and Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/template-customization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-template-customization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"File list ","type":"text"},{"text":"template","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom upload UI with ","type":"text"},{"text":"showFileList: false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customizing action buttons (","type":"text"},{"text":"buttons","type":"text","marks":[{"type":"code_inline"}]},{"text":" property)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Progress bar customization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hiding the default drop area","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Style and appearance overrides","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Advanced How-To Scenarios","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/advanced-how-to.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-advanced-how-to.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Programmatic file upload (","type":"text"},{"text":"upload","type":"text","marks":[{"type":"code_inline"}]},{"text":" method, ","type":"text"},{"text":"getFilesData","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Invisible/background upload","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Image preview before uploading","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resize images before upload","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Sort selected files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check file size / MIME type before upload","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Confirm dialog before file removal","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open/edit uploaded files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Trigger file browser from external button","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Convert uploaded image to binary","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"JWT authentication for secure upload ⚠️ ","type":"text"},{"text":"Never hardcode tokens. Retrieve from a secure session store at runtime. Do not log request headers or token values.","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Form support (HTML form, template-driven, reactive)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Localization (custom locale strings)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Accessibility and keyboard navigation","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/uploader-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties (","type":"text"},{"text":"allowedExtensions","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"asyncSettings","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"autoUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"buttons","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"directoryUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"dropArea","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"dropEffect","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"files","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"locale","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"maxFileSize","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"minFileSize","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"multiple","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"sequentialUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showFileList","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"template","type":"text","marks":[{"type":"code_inline"}]},{"text":", and more)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All methods (","type":"text"},{"text":"upload","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"remove","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cancel","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pause","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"resume","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"retry","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"clearAll","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getFilesData","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"bytesToSize","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"createFileList","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"sortFileList","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All events (","type":"text"},{"text":"uploading","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"success","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"failure","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"selected","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"removing","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"progress","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"chunkSuccess","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"chunkFailure","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"chunkUploading","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"actionComplete","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"beforeRemove","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"beforeUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"canceling","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"clearing","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"fileListRendering","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pausing","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"resuming","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start Example","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { UploaderComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-base/styles/material.css';\nimport '@syncfusion/ej2-buttons/styles/material.css';\nimport '@syncfusion/ej2-inputs/styles/material.css';\nimport '@syncfusion/ej2-popups/styles/material.css';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n\nfunction App() {\n // ⚠️ Replace with your own server-side endpoints.\n // Never use third-party demo URLs in production — files will be sent to that external server.\n const asyncSettings = {\n saveUrl: '/api/upload/save',\n removeUrl: '/api/upload/remove'\n };\n\n const onSuccess = (args: any) => {\n console.log('Upload operation:', args.operation, 'File:', args.file.name);\n };\n\n const onFailure = (args: any) => {\n console.error('Upload failed:', args.file.name);\n };\n\n return (\n \u003cUploaderComponent\n asyncSettings={asyncSettings}\n autoUpload={false}\n success={onSuccess}\n failure={onFailure}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Auto Upload with Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cUploaderComponent\n asyncSettings={{ saveUrl: '/api/upload/save', removeUrl: '/api/upload/remove' }}\n allowedExtensions=\".pdf,.doc,.docx\"\n maxFileSize={5000000}\n multiple={true}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Manual Upload with Custom Buttons","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cUploaderComponent\n asyncSettings={{ saveUrl: '/api/upload/save', removeUrl: '/api/upload/remove' }}\n autoUpload={false}\n buttons={{ browse: 'Choose File', clear: 'Clear All', upload: 'Upload All' }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Chunk Upload for Large Files","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cUploaderComponent\n asyncSettings={{\n saveUrl: '/api/upload/save',\n removeUrl: '/api/upload/remove',\n chunkSize: 500000 // 500 KB chunks\n }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Decision Guide","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Need","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property/Event","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Server URLs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"asyncSettings.saveUrl","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"asyncSettings.removeUrl","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Auto vs manual upload","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"autoUpload","type":"text","marks":[{"type":"code_inline"}]},{"text":" (default: ","type":"text"},{"text":"true","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Large file upload","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"asyncSettings.chunkSize","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Restrict file types","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"allowedExtensions","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Limit file size","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"maxFileSize","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"minFileSize","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Preload files from server","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"files","type":"text","marks":[{"type":"code_inline"}]},{"text":" prop","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Upload one at a time","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sequentialUpload: true","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Entire folder upload","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"directoryUpload: true","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom drop target","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dropArea","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom file list UI","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"template","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"showFileList: false","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add auth headers","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uploading","type":"text","marks":[{"type":"code_inline"}]},{"text":" event → ","type":"text"},{"text":"args.currentRequest.setRequestHeader()","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Send extra form data","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uploading","type":"text","marks":[{"type":"code_inline"}]},{"text":" event → ","type":"text"},{"text":"args.customFormData","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"NumericTextBox","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ","type":"text"},{"text":"NumericTextBoxComponent","type":"text","marks":[{"type":"strong"}]},{"text":" is a specialized input control for numeric data entry with support for number formatting (currency, percentage, scientific notation), min/max range validation, spin buttons, decimal precision control, internationalization, RTL languages, and full WCAG 2.2 accessibility compliance.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Documentation & Navigation Guide","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Agentic use:","type":"text","marks":[{"type":"strong"}]},{"text":" Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation).","type":"text"}]}]},{"type":"paragraph","content":[{"text":"When the user needs help with NumericTextBox, guide them to the appropriate reference:","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation and package setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS imports and themes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React component import and basic JSX","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating your first NumericTextBox","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the application","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Formats & Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/formats-and-validation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-formats-and-validation.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standard format specifiers (currency, percentage, number, scientific)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom number formats with # and 0 patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Range validation with min and max properties","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"strictMode for enforcing valid ranges","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Real-world formatting examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Spin Buttons & Step Control","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/spin-buttons-and-step.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-spin-buttons-and-step.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling/disabling spin button arrows","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Step property for increment values","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customizing spin button appearance and behavior","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Precision with step increments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard shortcuts (Arrow Up/Down)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Adornments & Styling","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/adornments-and-styling.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-adornments-and-styling.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefix and suffix text (units, currency symbols)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS classes and custom styling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Placeholder, disabled, and readonly states","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Focus and blur event handling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Theme customization and appearance options","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Precision & Decimals","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/precision-decimals.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-precision-decimals.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"decimals property for controlling decimal places","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"validateDecimalOnType for real-time precision validation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Maintaining trailing zeros in display","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rounding behavior and edge cases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Precision during input vs display","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Two-Way Binding & Forms","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/two-way-binding-forms.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-two-way-binding-forms.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Two-way value binding in React (value prop + onChange)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Controlled component patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React state management","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React Hook Form integration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Form validation with NumericTextBox","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Globalization & Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/globalization-accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-globalization-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Internationalization and locale support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Right-to-Left (RTL) language support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 accessibility compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation and shortcuts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support with ARIA attributes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Focus management and color contrast","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Complete properties reference (value, min, max, step, format, decimals, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods reference (increment, decrement, getText, focusIn, focusOut, destroy, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events reference with full argument types (change, blur, focus, created, destroyed)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start Example","type":"text"}]},{"type":"paragraph","content":[{"text":"Here's a minimal working example to get started:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"import React, { useState } from 'react';\nimport { NumericTextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-base/styles/material3.css';\nimport '@syncfusion/ej2-buttons/styles/material3.css';\nimport '@syncfusion/ej2-inputs/styles/material3.css';\n\nexport default function App() {\n const [value, setValue] = useState(10);\n\n return (\n \u003cdiv style={{ padding: '20px' }}>\n \u003ch3>Enter a Number\u003c/h3>\n \u003cNumericTextBoxComponent\n value={value}\n onChange={(e) => setValue(e.value)}\n min={0}\n max={100}\n step={1}\n />\n \u003cp>Current Value: {value}\u003c/p>\n \u003c/div>\n );\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Key points:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Import ","type":"text"},{"text":"NumericTextBoxComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" from ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Import required CSS themes (material3 in this example)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":" prop for the current numeric value","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"onChange","type":"text","marks":[{"type":"code_inline"}]},{"text":" event to update React state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ","type":"text"},{"text":"min","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"max","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"step","type":"text","marks":[{"type":"code_inline"}]},{"text":" for validation and controls","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"1. Currency Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"\u003cNumericTextBoxComponent\n value={99.99}\n format=\"c2\"\n min={0}\n placeholder=\"Enter amount\"\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2. Percentage Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"\u003cNumericTextBoxComponent\n value={50}\n format=\"p\"\n min={0}\n max={100}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"3. Integer-Only Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"\u003cNumericTextBoxComponent\n value={10}\n decimals={0}\n step={1}\n min={0}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"4. Bounded Range with Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"\u003cNumericTextBoxComponent\n value={25}\n min={0}\n max={100}\n strictMode={true}\n placeholder=\"0-100\"\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"5. Form Field with Label","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"jsx"},"content":[{"text":"\u003cdiv>\n \u003clabel>Product Quantity:\u003c/label>\n \u003cNumericTextBoxComponent\n value={qty}\n onChange={(e) => setQty(e.value)}\n min={1}\n step={1}\n prefix=\"Units: \"\n />\n\u003c/div>","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Properties Reference","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Current numeric value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"min","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Minimum allowed value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maximum allowed value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"step","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Increment/decrement step (default: 1)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"decimals","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Number of decimal places when focused","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"format","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Number format (n2, c2, p2, e2, etc.)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"currency","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ISO 4217 currency code (e.g., 'USD', 'EUR')","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Placeholder text when empty","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FloatLabelType","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Float label behavior ('Never', 'Always', 'Auto')","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prevent user input","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable or disable the control (default: true)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"strictMode","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enforce min/max validation (default: true)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"validateDecimalOnType","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Restrict decimal length during typing","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showSpinButton","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show/hide spinner arrows (default: true)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show/hide clear icon","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"allowMouseWheel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable mouse wheel increment/decrement (default: true)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Additional CSS classes for custom styling","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"width","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number | string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Width of the component","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Use Cases","type":"text"}]},{"type":"paragraph","content":[{"text":"1. Shopping Cart - Quantity Input","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integer-only, min=1, step=1, spinner for easy adjustment","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"2. Price Calculator - Currency Field","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"format=\"c2\", min=0, prefix=\"$\", two decimal places","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"3. Rating or Score - 0-100 Range","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"min=0, max=100, strictMode=true, no decimals","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"4. Discount Percentage","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"format=\"p\", min=0, max=100, two decimal places","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"5. Measurement Input","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"decimals=2, suffix=\" cm\", min=0, spinner for precision","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"6. Financial Form","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"format=\"c2\", validation, form integration, accessibility","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Next Steps","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Package requirement:","type":"text","marks":[{"type":"strong"}]},{"text":" The packages ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"@syncfusion/ej2-base","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"@syncfusion/ej2-buttons","type":"text","marks":[{"type":"code_inline"}]},{"text":" must be present in your project's ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]},{"text":". Confirm they are already installed and that your lockfile (e.g., ","type":"text"},{"text":"package-lock.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"yarn.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":") pins their versions for supply-chain integrity. When adding them, use an explicit version range such as ","type":"text"},{"text":"@syncfusion/ej2-react-inputs@^27.x.x","type":"text","marks":[{"type":"code_inline"}]},{"text":" to avoid unpinned dependency risks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Getting Started reference:","type":"text","marks":[{"type":"strong"}]},{"text":" For installation details and basic setup, see ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/numerictextbox-getting-started.md","title":null}}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Choose your reference:","type":"text","marks":[{"type":"strong"}]},{"text":" Based on your use case (formatting, validation, forms, etc.), navigate to the relevant reference section above.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Review examples:","type":"text","marks":[{"type":"strong"}]},{"text":" Each reference contains ready-to-use code samples that can be adapted to your requirements.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize:","type":"text","marks":[{"type":"strong"}]},{"text":" Modify the examples to fit your specific use case and application needs.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"paragraph","content":[{"text":"For detailed implementation guidance, navigate to the appropriate reference file above.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"TextBox","type":"text"}]},{"type":"paragraph","content":[{"text":"The TextBox component is a lightweight input control that captures user text input with support for floating labels, validation states, icons, and advanced features. This skill guides you through implementing, configuring, and customizing the TextBox component in React applications.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Agentic use:","type":"text","marks":[{"type":"strong"}]},{"text":" Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation).","type":"text"}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Vite setup for React development","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installing ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"text":" package 🛑 ","type":"text"},{"text":"STOP — Do not install packages autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm install @syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":". Pin a specific version (e.g., ","type":"text","marks":[{"type":"em"}]},{"text":"@syncfusion/[email protected]","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":") and verify with ","type":"text","marks":[{"type":"em"}]},{"text":"npm audit","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adding CSS imports and themes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating your first TextBox component","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adding icons and floating labels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the development server 🛑 ","type":"text"},{"text":"STOP — Do not start the dev server autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm run dev","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Features and Groups","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/features-and-groups.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-features-and-groups.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Floating label behavior (Never, Always, Auto)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Icons with ","type":"text"},{"text":"addIcon()","type":"text","marks":[{"type":"code_inline"}]},{"text":" method (prepend/append)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear button with ","type":"text"},{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rounded corner with ","type":"text"},{"text":"e-corner","type":"text","marks":[{"type":"code_inline"}]},{"text":" CSS class","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled state with ","type":"text"},{"text":"enabled={false}","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multi-line textbox creation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"TextBox with clear button and floating label combinations","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Styling and Sizing","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/styling-and-sizing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-styling-and-sizing.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Three predefined sizes: Normal, Small (","type":"text"},{"text":"e-small","type":"text","marks":[{"type":"code_inline"}]},{"text":"), Large (","type":"text"},{"text":"e-bigger","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Applying size classes via ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rounded corner with ","type":"text"},{"text":"e-corner","type":"text","marks":[{"type":"code_inline"}]},{"text":" CSS class","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS customization for TextBox wrapper and floating label","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom CSS classes and themes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Responsive design patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Multiline TextBox","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/multiline-textbox.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-multiline-textbox.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating multiline/textarea inputs with ","type":"text"},{"text":"multiline={true}","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Floating labels with multiline","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Auto-resizing textboxes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabling resize functionality","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Limiting text length with ","type":"text"},{"text":"htmlAttributes={{ maxlength: '...' }}","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Character counting and display","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Validation and States","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/validation-and-states.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-validation-and-states.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Error, warning, and success validation states via ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Applying validation classes (","type":"text"},{"text":"e-error","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-warning","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-success","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled state with ","type":"text"},{"text":"enabled={false}","type":"text","marks":[{"type":"code_inline"}]},{"text":" (not ","type":"text"},{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read-only state with ","type":"text"},{"text":"readonly={true}","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Differences between disabled and read-only","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dynamic color changes based on values using ","type":"text"},{"text":"input","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Advanced Features","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/advanced-features.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-advanced-features.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adornments: ","type":"text"},{"text":"prependTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"appendTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":" properties","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interactive adornments (password toggle, delete button)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React functional components with hooks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"useState","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"useEffect","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"useRef","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"useReducer","type":"text","marks":[{"type":"code_inline"}]},{"text":" integration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Event handling (created, input, change events)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Form validation patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility and Migration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility-and-migration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-accessibility-and-migration.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2, Section 508, and WAI-ARIA compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support and ARIA attributes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Right-to-Left (RTL) support with ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Migrating from CSS TextBox to React component","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before/after code comparison","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textbox-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties: ","type":"text"},{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"type","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"multiline","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"autocomplete","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"locale","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"width","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"prependTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"appendTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods: ","type":"text"},{"text":"addIcon","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"addAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"removeAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusIn","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusOut","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroy","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getPersistData","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events: ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroyed","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"input","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focus","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"blur","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Basic TextBox with Floating Label","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport './App.css';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent \n placeholder=\"Enter your name\" \n floatLabelType=\"Auto\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"TextBox with Icon","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function App() {\n const textboxRef = useRef(null);\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addIcon('append', 'e-icons e-input-popup-date');\n }\n };\n\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter date\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"TextBox with Clear Button","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter your email\"\n floatLabelType=\"Auto\"\n showClearButton={true}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Multiline TextBox","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function App() {\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your address\"\n floatLabelType=\"Auto\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Form with Validation States","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useState } from 'react';\n\nexport default function ValidationForm() {\n const [cssClass, setCssClass] = useState('');\n\n return (\n \u003cdiv>\n \u003cTextBoxComponent\n placeholder=\"Enter username\"\n cssClass={cssClass}\n floatLabelType=\"Auto\"\n input={(e: any) => {\n if (!e.value) setCssClass('');\n else if (e.value.length \u003c 3) setCssClass('e-error');\n else if (e.value.length \u003c 6) setCssClass('e-warning');\n else setCssClass('e-success');\n }}\n />\n \u003c/div>\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Password TextBox with Toggle","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef, useState } from 'react';\n\nexport default function PasswordInput() {\n const textboxRef = useRef\u003cTextBoxComponent>(null);\n const [isVisible, setIsVisible] = useState(false);\n\n const toggleVisibility = () => {\n if (textboxRef.current) {\n const newVisibility = !isVisible;\n textboxRef.current.type = newVisibility ? 'text' : 'password';\n setIsVisible(newVisibility);\n }\n };\n\n function appendTemplate(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan\n className={`e-icons ${isVisible ? 'e-eye-slash' : 'e-eye'}`}\n onClick={toggleVisibility}\n style={{ cursor: 'pointer' }}\n >\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n ref={textboxRef}\n type=\"password\"\n placeholder=\"Enter password\"\n floatLabelType=\"Auto\"\n appendTemplate={appendTemplate}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Email Input with Unit Label","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import * as React from 'react';\nimport { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function EmailInput() {\n function prependTemplate(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-icons e-user\">\u003c/span>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003c/>\n );\n }\n\n function appendTemplate(): JSX.Element {\n return (\n \u003c>\n \u003cspan className=\"e-input-separator\">\u003c/span>\n \u003cspan>.com\u003c/span>\n \u003c/>\n );\n }\n\n return (\n \u003cTextBoxComponent\n type=\"email\"\n placeholder=\"Enter email\"\n floatLabelType=\"Auto\"\n prependTemplate={prependTemplate}\n appendTemplate={appendTemplate}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Rounded Corner TextBox","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function RoundedCornerTextBox() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Date\"\n cssClass=\"e-corner\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Disabled TextBox","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function DisabledTextBox() {\n return (\n \u003cTextBoxComponent\n placeholder=\"Enter Name\"\n enabled={false}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"RTL TextBox","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\n\nexport default function RTLTextBox() {\n return (\n \u003cTextBoxComponent\n placeholder=\"أدخل اسمك\"\n floatLabelType=\"Auto\"\n enableRtl={true}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Auto-sizing Multiline TextBox","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport { useRef } from 'react';\n\nexport default function AutoSizeTextbox() {\n const textboxRef = useRef(null);\n\n const handleInput = () => {\n if (textboxRef.current) {\n const elem = textboxRef.current.respectiveElement;\n elem.style.height = 'auto';\n elem.style.height = elem.scrollHeight + 'px';\n }\n };\n\n const handleCreate = () => {\n if (textboxRef.current) {\n textboxRef.current.addAttributes({ rows: 1 });\n }\n handleInput();\n };\n\n return (\n \u003cTextBoxComponent\n multiline={true}\n placeholder=\"Enter your message\"\n floatLabelType=\"Auto\"\n ref={textboxRef}\n created={handleCreate}\n input={handleInput}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Properties","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hint text shown when input is empty","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Never\" | \"Always\" | \"Auto\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Label animation behavior","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sets the content of the TextBox","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"type","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Input type (","type":"text"},{"text":"text","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"password","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"email","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"number","type":"text","marks":[{"type":"code_inline"}]},{"text":", etc.)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"multiline","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Convert to textarea for multi-line input","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Display clear button when input has value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Apply CSS classes for sizing/validation/appearance (e.g., ","type":"text"},{"text":"\"e-error\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"\"e-small\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"\"e-corner\"","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable (","type":"text"},{"text":"true","type":"text","marks":[{"type":"code_inline"}]},{"text":") or disable (","type":"text"},{"text":"false","type":"text","marks":[{"type":"code_inline"}]},{"text":") input interaction","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Allow selection but prevent editing","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable right-to-left rendering","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Persist value state between page reloads ⚠️ ","type":"text"},{"text":"Stores data in browser storage — enable only with explicit user consent","type":"text","marks":[{"type":"em"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"autocomplete","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Control browser autocomplete (","type":"text"},{"text":"\"on\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" | ","type":"text"},{"text":"\"off\"","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{ [key: string]: string }","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pass additional HTML attributes (e.g., ","type":"text"},{"text":"{ maxlength: '200' }","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"locale","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Override global culture/localization value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"width","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number | string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Set component width","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"prependTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"() => JSX.Element","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Render element before input","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"appendTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"() => JSX.Element","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Render element after input","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Events","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Event","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Arguments","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Object","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires after component initialization","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"destroyed","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Object","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires when component is destroyed","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"change","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ChangedEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires when value changes on focus-out","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"input","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"InputEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires on every keystroke","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"focus","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FocusInEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires when TextBox gains focus","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"blur","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FocusOutEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fires when TextBox loses focus","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Related Documentation","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"ℹ️ External links below are for manual reference only.","type":"text","marks":[{"type":"strong"}]},{"text":" Do not auto-fetch these URLs in an agentic pipeline without explicit user consent.","type":"text"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Syncfusion React TextBox Component Demo","type":"text","marks":[{"type":"link","attrs":{"href":"https://ej2.syncfusion.com/react/demos/#/tailwind3/textboxes/default","title":null}}]},{"text":" ","type":"text"},{"text":"(external)","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React TextBox API Reference","type":"text","marks":[{"type":"link","attrs":{"href":"https://ej2.syncfusion.com/react/documentation/api/textbox/","title":null}}]},{"text":" ","type":"text"},{"text":"(external)","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Syncfusion React Inputs Package","type":"text","marks":[{"type":"link","attrs":{"href":"https://www.npmjs.com/package/@syncfusion/ej2-react-inputs","title":null}}]},{"text":" ","type":"text"},{"text":"(external — verify before installing)","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React Functional Components","type":"text","marks":[{"type":"link","attrs":{"href":"./references/textbox-advanced-features.md","title":null}}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"CheckBox","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ","type":"text"},{"text":"CheckBoxComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a graphical UI element that allows users to select one or more options. It supports ","type":"text"},{"text":"checked","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"unchecked","type":"text","marks":[{"type":"strong"}]},{"text":", and ","type":"text"},{"text":"indeterminate","type":"text","marks":[{"type":"strong"}]},{"text":" states, flexible label positioning, size variants, full accessibility compliance, and rich CSS customization.","type":"text"}]},{"type":"paragraph","content":[{"text":"Package:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"@syncfusion/ej2-react-buttons","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Agentic use:","type":"text","marks":[{"type":"strong"}]},{"text":" Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation).","type":"text"}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installing ","type":"text"},{"text":"@syncfusion/ej2-react-buttons","type":"text","marks":[{"type":"code_inline"}]},{"text":" 🛑 ","type":"text"},{"text":"STOP — Do not install packages autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm install @syncfusion/ej2-react-buttons --save","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":". Verify with ","type":"text","marks":[{"type":"em"}]},{"text":"npm audit","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports for Tailwind3","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal ","type":"text"},{"text":"CheckBoxComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the Vite/React app 🛑 ","type":"text"},{"text":"STOP — Do not start the dev server autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm run dev","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"States (Checked, Unchecked, Indeterminate, Disabled)","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/states.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-states.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting ","type":"text"},{"text":"checked={true}","type":"text","marks":[{"type":"code_inline"}]},{"text":" for checked state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting ","type":"text"},{"text":"indeterminate={true}","type":"text","marks":[{"type":"code_inline"}]},{"text":" for indeterminate state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting ","type":"text"},{"text":"disabled={true}","type":"text","marks":[{"type":"code_inline"}]},{"text":" for disabled state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Combined state examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Label and Size","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/label-and-size.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-label-and-size.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"label","type":"text","marks":[{"type":"code_inline"}]},{"text":" prop for caption text","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"labelPosition","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"\"Before\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"\"After\"","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Small size via ","type":"text"},{"text":"cssClass=\"e-small\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Default vs. small size examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Style and Appearance","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/style-and-appearance.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-style-and-appearance.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Available CSS classes for overriding checkbox styles","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Color variant customization (primary, success, warning, danger, info)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom frame shapes (round checkbox)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom check icon","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Theme Studio integration","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility and RTL","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 / Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WAI-ARIA attributes (","type":"text"},{"text":"aria-disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation (Space key)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Right-to-left (","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":") support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"How-To Guides","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/how-to.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-how-to.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Name and value in form submission","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling right-to-left display","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Building customized checkbox variants","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/checkbox-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties: ","type":"text"},{"text":"checked","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableHtmlSanitizer","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"indeterminate","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"label","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"labelPosition","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"locale","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"name","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods: ","type":"text"},{"text":"click()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroy()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusIn()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events: ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"npm install @syncfusion/ej2-react-buttons --save\n# Then run: npm audit","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"css"},"content":[{"text":"/* src/App.css */\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css\";","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cCheckBoxComponent label=\"Accept Terms\" />\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Controlled Checkbox with Change Handler","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport { ChangeEventArgs } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n const [isChecked, setIsChecked] = React.useState(false);\n\n const handleChange = (args: ChangeEventArgs) => {\n setIsChecked(args.checked);\n };\n\n return (\n \u003cCheckBoxComponent\n label=\"Subscribe to newsletter\"\n checked={isChecked}\n change={handleChange}\n />\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Parent / Children with Indeterminate State","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cul>\n {/* Parent: indeterminate when some children are selected */}\n \u003cli>\u003cCheckBoxComponent label=\"Select All\" indeterminate={true} />\u003c/li>\n \u003cli>\u003cCheckBoxComponent label=\"Option A\" checked={true} />\u003c/li>\n \u003cli>\u003cCheckBoxComponent label=\"Option B\" />\u003c/li>\n \u003c/ul>\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Form Submission with Name and Value","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { CheckBoxComponent, ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cform>\n \u003cCheckBoxComponent name=\"hobby\" value=\"Reading\" label=\"Reading\" checked={true} />\n \u003cCheckBoxComponent name=\"hobby\" value=\"Gaming\" label=\"Gaming\" />\n \u003cButtonComponent isPrimary={true}>Submit\u003c/ButtonComponent>\n \u003c/form>\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Props at a Glance","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prop","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"label","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Caption text next to checkbox","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"checked","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Checked state","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"indeterminate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Indeterminate (partial) state","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Disabled state","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"labelPosition","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Before' | 'After'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'After'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Label placement","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom CSS class(es)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"name","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Form field name","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Form field value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right-to-left rendering","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Persist state across reloads ⚠️ ","type":"text"},{"text":"Stores data in browser storage — enable only with explicit user consent","type":"text","marks":[{"type":"em"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Signature","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ","type":"text"},{"text":"SignatureComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" renders a canvas-based signature pad that captures smooth handwritten signatures using variable-width bezier curves. It supports drawing, saving (PNG/JPEG/SVG/base64/blob), loading existing signatures, undo/redo history, customizable stroke and background appearance, and full accessibility compliance.","type":"text"}]},{"type":"paragraph","content":[{"text":"Package:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"🛑 ","type":"text"},{"text":"Agentic use:","type":"text","marks":[{"type":"strong"}]},{"text":" Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation).","type":"text"}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installing ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"text":" 🛑 ","type":"text"},{"text":"STOP — Do not install packages autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm install @syncfusion/ej2-react-inputs --save","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":". Verify with ","type":"text","marks":[{"type":"em"}]},{"text":"npm audit","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports (Tailwind3)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal ","type":"text"},{"text":"SignatureComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the application 🛑 ","type":"text"},{"text":"STOP — Do not start the dev server autonomously. Ask the user to run: ","type":"text","marks":[{"type":"em"}]},{"text":"npm run dev","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/customization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-customization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stroke width: ","type":"text"},{"text":"maxStrokeWidth","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"minStrokeWidth","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"velocity","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stroke color: ","type":"text"},{"text":"strokeColor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Background color: ","type":"text"},{"text":"backgroundColor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Background image: ","type":"text"},{"text":"backgroundImage","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Open and Save","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/open-save.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-open-save.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Load signature from base64 or URL (","type":"text"},{"text":"load","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save as base64 (","type":"text"},{"text":"getSignature","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save as Blob (","type":"text"},{"text":"saveAsBlob","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getBlob","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save as image file — PNG, JPEG, SVG (","type":"text"},{"text":"save","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save with background (","type":"text"},{"text":"saveWithBackground","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"User Interaction","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/user-interaction.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-user-interaction.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Undo/redo strokes (","type":"text"},{"text":"undo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"redo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"canUndo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"canRedo","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear the canvas (","type":"text"},{"text":"clear","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"isEmpty","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled state (","type":"text"},{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read-only mode (","type":"text"},{"text":"isReadOnly","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Draw text as signature (","type":"text"},{"text":"draw","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard shortcuts (Ctrl+Z, Ctrl+Y, Ctrl+S, Delete)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Toolbar Integration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/toolbar-integration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-toolbar-integration.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integrating with Syncfusion ","type":"text"},{"text":"ToolbarComponent","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Wiring undo, redo, clear, and save toolbar buttons","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stroke color picker using ","type":"text"},{"text":"ColorPickerComponent","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Background color picker integration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stroke width dropdown with ","type":"text"},{"text":"DropDownListComponent","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling/disabling toolbar buttons based on signature state","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 / Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard interaction (Ctrl+Z, Ctrl+Y, Ctrl+S, Delete)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader and mobile device support","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/signature-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties: ","type":"text"},{"text":"backgroundColor","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"backgroundImage","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"isReadOnly","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"maxStrokeWidth","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"minStrokeWidth","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"saveWithBackground","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"strokeColor","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"velocity","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All methods: ","type":"text"},{"text":"canRedo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"canUndo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"clear","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroy","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"draw","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getBlob","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getSignature","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"isEmpty","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"load","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"redo","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"refresh","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"save","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"saveAsBlob","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"undo","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events: ","type":"text"},{"text":"beforeSave","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"npm install @syncfusion/ej2-react-inputs --save\n# Then run: npm audit","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"css"},"content":[{"text":"/* src/App.css */\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css\";","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cSignatureComponent id=\"signature\" />\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Signature with Undo/Redo/Clear Controls","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { SignatureComponent, SignatureChangeEventArgs } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\nimport { useRef } from 'react';\n\nfunction App() {\n const sigRef = React.useRef\u003cSignatureComponent>(null);\n const [canUndo, setCanUndo] = React.useState(false);\n const [canRedo, setCanRedo] = React.useState(false);\n const [isEmpty, setIsEmpty] = React.useState(true);\n\n function handleChange(args: SignatureChangeEventArgs) {\n if (sigRef.current) {\n setCanUndo(sigRef.current.canUndo());\n setCanRedo(sigRef.current.canRedo());\n setIsEmpty(sigRef.current.isEmpty());\n }\n }\n\n return (\n \u003cdiv>\n \u003cButtonComponent disabled={!canUndo} onClick={() => sigRef.current?.undo()}>Undo\u003c/ButtonComponent>\n \u003cButtonComponent disabled={!canRedo} onClick={() => sigRef.current?.redo()}>Redo\u003c/ButtonComponent>\n \u003cButtonComponent disabled={isEmpty} onClick={() => sigRef.current?.clear()}>Clear\u003c/ButtonComponent>\n \u003cSignatureComponent id=\"signature\" ref={sigRef} change={handleChange} />\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Save Signature as PNG","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { SignatureComponent } from '@syncfusion/ej2-react-inputs';\nimport { ButtonComponent } from '@syncfusion/ej2-react-buttons';\nimport * as React from 'react';\n\nfunction App() {\n const sigRef = React.useRef\u003cSignatureComponent>(null);\n\n function saveSignature() {\n sigRef.current?.save('Png', 'MySignature');\n }\n\n return (\n \u003cdiv>\n \u003cSignatureComponent id=\"signature\" ref={sigRef} />\n \u003cButtonComponent onClick={saveSignature}>Save as PNG\u003c/ButtonComponent>\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Props at a Glance","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prop","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"strokeColor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'#000000'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pen/stroke color (hex, rgb, or name)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"backgroundColor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Canvas background color","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"backgroundImage","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Canvas background image URL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"maxStrokeWidth","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maximum stroke thickness","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"minStrokeWidth","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Minimum stroke thickness","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"velocity","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.7","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Controls stroke width variation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Disables the component","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"isReadOnly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prevents drawing, allows focus","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"saveWithBackground","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Include background when saving","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Persist state across page reloads ⚠️ ","type":"text"},{"text":"Stores signature data (biometric input) in browser storage — enable only with explicit user consent and applicable privacy disclosures","type":"text","marks":[{"type":"em"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"OTP Input","type":"text"}]},{"type":"paragraph","content":[{"text":"A focused input component for collecting one-time passwords, PINs, and verification codes. Renders a configurable number of individual character input fields with full keyboard navigation, accessibility support, and visual styling modes.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { OtpInputComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv id=\"container\">\n \u003cOtpInputComponent id=\"otpinput\" />\n \u003c/div>\n );\n}\n\nexport default App;","type":"text"}]},{"type":"paragraph","content":[{"text":"CSS (src/App.css):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"css"},"content":[{"text":"@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css\";","type":"text"}]},{"type":"paragraph","content":[{"text":"Install:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"npm install @syncfusion/ej2-react-inputs --save","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"6-digit OTP with verification callback","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { OtpInputComponent, OtpChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const handleValueChanged = (args: OtpChangedEventArgs) => {\n console.log('Complete OTP:', args.value);\n // Call your API verification here\n };\n\n return (\n \u003cOtpInputComponent\n id=\"otpinput\"\n length={6}\n autoFocus={true}\n valueChanged={handleValueChanged}\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Password-masked OTP with error state","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { OtpInputComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cOtpInputComponent\n id=\"otpinput\"\n type=\"password\"\n length={6}\n cssClass=\"e-error\"\n placeholder=\"*\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Alphanumeric OTP with separator","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { OtpInputComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cOtpInputComponent\n id=\"otpinput\"\n type=\"text\"\n length={6}\n separator=\"-\"\n textTransform=\"uppercase\"\n stylingMode=\"filled\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Properties","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"length","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Number of OTP input fields","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string | number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Current OTP value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"type","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'number' | 'text' | 'password'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'number'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Input character type","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"stylingMode","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'outlined' | 'filled' | 'underlined'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'outlined'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visual style variant","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hint character(s) per field","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"separator","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Character between fields","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom/predefined CSS class (","type":"text"},{"text":"e-success","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-warning","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-error","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Disables user input","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"autoFocus","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Auto-focuses on render","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right-to-left layout","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"textTransform","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'none' | 'uppercase' | 'lowercase'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'none'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Case transformation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ariaLabels","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Per-field ARIA labels","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{ [key: string]: string }","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{}","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Extra HTML attributes","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Installation, Setup & Basic Usage","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/otp-input-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"npm install and Vite project setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal working example","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting OTP length","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting a default value","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Auto-focus on load","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Troubleshooting","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Input Types, Styling & Visual Configuration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/configuration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/otp-input-configuration.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Input types: number, text, password","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Styling modes: outlined, filled, underlined","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Placeholder text (single/per-field)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Separator characters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS class customization (","type":"text"},{"text":"e-success","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-warning","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"e-error","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RTL support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Text transform (uppercase/lowercase)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"State persistence","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Events & Interaction Handling","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/events.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/otp-input-events.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":" event (post-render init)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"focus","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"blur","type":"text","marks":[{"type":"code_inline"}]},{"text":" events with ","type":"text"},{"text":"OtpFocusEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"input","type":"text","marks":[{"type":"code_inline"}]},{"text":" event for real-time tracking with ","type":"text"},{"text":"OtpInputEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"valueChanged","type":"text","marks":[{"type":"code_inline"}]},{"text":" event for OTP submission with ","type":"text"},{"text":"OtpChangedEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Programmatic focus via ","type":"text"},{"text":"focusIn()","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"focusOut()","type":"text","marks":[{"type":"code_inline"}]},{"text":" methods","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Patterns: conditional submit button, verification feedback","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/otp-input-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2, Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WAI-ARIA roles and attributes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation shortcuts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Per-field ","type":"text"},{"text":"ariaLabels","type":"text","marks":[{"type":"code_inline"}]},{"text":" configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":" for custom accessibility metadata","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RTL support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Axe-core and accessibility-checker validation","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Full API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/otp-input-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties with types, defaults, and examples","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods: ","type":"text"},{"text":"destroy()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusIn()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusOut()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All events and their argument interfaces","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Type enumerations: ","type":"text"},{"text":"OtpInputType","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"OtpInputStyle","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"TextTransform","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Event argument interfaces: ","type":"text"},{"text":"OtpFocusEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"OtpInputEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"OtpChangedEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Decision Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"Which type to use?","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User enters digits only → ","type":"text"},{"text":"type=\"number\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" (default)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User enters letters + digits → ","type":"text"},{"text":"type=\"text\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Input should be hidden/masked → ","type":"text"},{"text":"type=\"password\"","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Which event to use?","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Trigger verification when OTP is fully entered → ","type":"text"},{"text":"valueChanged","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Track partial input in real time → ","type":"text"},{"text":"input","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Know when user clicks into/out of a field → ","type":"text"},{"text":"focus","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"blur","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Which styling mode?","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standard forms → ","type":"text"},{"text":"outlined","type":"text","marks":[{"type":"code_inline"}]},{"text":" (default)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Card/dashboard UI → ","type":"text"},{"text":"filled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Material Design forms → ","type":"text"},{"text":"underlined","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Visual feedback after verification?","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Correct OTP → set ","type":"text"},{"text":"cssClass=\"e-success\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Wrong OTP → set ","type":"text"},{"text":"cssClass=\"e-error\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pending/caution → set ","type":"text"},{"text":"cssClass=\"e-warning\"","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"TextArea","type":"text"}]},{"type":"paragraph","content":[{"text":"The TextArea component enables efficient collection of multiline text input in forms and applications. It provides essential features for user feedback, comments, descriptions, and any scenario requiring extended text input.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation and npm setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Vite/React project configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Basic TextArea implementation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS imports and theming","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Getting and setting values with properties, state, and events","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Core Features & Content","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/value-and-content.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-value-and-content.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting initial values with property and state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Getting current value from textarea","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Value binding patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Change detection and state management","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Floating Labels & Placeholders","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/floating-label.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-floating-label.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Floating label types (Auto, Always, Never)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Placeholder behavior during user interaction","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Localization with floating labels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Placeholder text translations for different cultures","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Adornments (Custom Elements)","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/adornments.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-adornments.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adding icons, buttons, or text before/after textarea","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prepend and append templates","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adornment flow and orientation (horizontal/vertical)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Common use cases: character count, formatting tools, validation icons","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Form Integration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/form-support.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-form-support.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"HTML form submission with textarea","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Name attribute and form data","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"FormValidator integration for validation rules","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Required fields, min/max length constraints","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation messaging and error states","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Content Constraints","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/max-length.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-max-length.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enforcing character limits with maxLength","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preventing user input beyond limit","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User feedback on character restrictions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Edge cases and best practices","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Sizing & Dimensions","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/rows-columns-sizing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-rows-columns-sizing.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting visible height with rows property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting visible width with cols property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Responsive sizing strategies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Controlling textarea dimensions","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Resize Behavior","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/resize.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-resize.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resize modes: Vertical, Horizontal, Both, None","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User-controlled resizing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Width customization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Layout considerations for fixed-size textareas","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Styling & Appearance","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/styling-appearance.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-styling-appearance.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Size classes (e-small, e-bigger)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Filled and outline appearance modes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom CSS with cssClass property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled and read-only states","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation state styling (success, warning, error)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear button configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Color customization and rounded corners","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Events & User Interaction","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/events.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-events.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"created: Initialization event","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"input: Real-time value change detection","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"change: Value change with focus-out","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"focus: Focus gained","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"blur: Focus lost","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"destroyed: Component cleanup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Event args and usage patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Methods & Programmatic Control","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/methods.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-methods.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"focusIn(): Programmatically set focus","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"focusOut(): Remove focus","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"getPersistData(): Retrieve persistence state","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"addAttributes(): Add HTML attributes dynamically","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"removeAttributes(): Remove HTML attributes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"destroy(): Clean up component","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Complete API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/textarea-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties with descriptions and defaults","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All methods with parameters and return types","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All events with arg types","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Type definitions and enums","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Usage examples for each API","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"import { TextAreaComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n const [textValue, setTextValue] = React.useState('');\n\n const handleChange = (args) => {\n console.log('TextArea value changed:', args.value);\n };\n\n return (\n \u003cdiv className='wrap'>\n \u003cTextAreaComponent\n id='default'\n placeholder='Enter your comments'\n value={textValue}\n change={handleChange}\n floatLabelType='Auto'\n rows={5}\n cols={40}\n />\n \u003c/div>\n );\n}\n\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 1: Form with Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"\u003cTextAreaComponent\n name='comments'\n placeholder='Your feedback'\n floatLabelType='Auto'\n required={true}\n maxLength={500}\n showClearButton={true}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 2: Controlled Component with State","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"const [value, setValue] = React.useState('');\n\n\u003cTextAreaComponent\n value={value}\n input={(args) => setValue(args.value)}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 3: Styled with Custom CSS","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"\u003cTextAreaComponent\n placeholder='Enter text'\n cssClass='e-outline e-small'\n floatLabelType='Auto'\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 4: Disabled & Read-Only States","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"\u003cTextAreaComponent placeholder='Disabled' enabled={false} />\n\u003cTextAreaComponent placeholder='Read-only' readonly={true} />","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 5: With Adornments","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"\u003cTextAreaComponent\n placeholder='Message'\n prependTemplate={() => \u003cspan className='icon'>📝\u003c/span>}\n appendTemplate={() => \u003cbutton>Send\u003c/button>}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Props Summary","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prop","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Common Values","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Set/get textarea content","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hint text","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rows","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visible height in lines","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3-10","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cols","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visible width in characters","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"30-80","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Floating behavior","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Auto', 'Always', 'Never'","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"maxLength","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Character limit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"resizeMode","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"User resizing","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Both', 'Vertical', 'Horizontal', 'None'","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable/disable input","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read-only mode","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom styling","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'e-outline', 'e-small', 'e-filled'","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Display clear button","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Slider (RangeSlider)","type":"text"}]},{"type":"paragraph","content":[{"text":"A comprehensive guide for implementing the Syncfusion Essential JS 2 ","type":"text"},{"text":"SliderComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" in React applications. Supports single-value (","type":"text"},{"text":"Default","type":"text","marks":[{"type":"code_inline"}]},{"text":"), min-range fill (","type":"text"},{"text":"MinRange","type":"text","marks":[{"type":"code_inline"}]},{"text":"), and dual-handle range selection (","type":"text"},{"text":"Range","type":"text","marks":[{"type":"code_inline"}]},{"text":") with tooltips, ticks, limits, color ranges, custom values, formatting, accessibility, events, and more.","type":"text"}]},{"type":"paragraph","content":[{"text":"Package:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation and package setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Basic implementation of three slider types","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS imports and theme setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal working example","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Initial configuration","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Types and Orientation","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/types-and-orientation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-types-and-orientation.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Three slider types: Default, MinRange, Range","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Understanding shadow/fill behavior","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Horizontal vs vertical orientation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Type selection guide","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Code examples for each type","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Tooltips and Ticks","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/tooltips-and-ticks.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-tooltips-and-ticks.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tooltip configuration and placement","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tooltip visibility modes (Always, Focus, Click)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tick marks and scale display","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"largeStep and smallStep configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Small tick visibility","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Combined tooltip + ticks examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Formatting and Limits","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/formatting-and-limits.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-formatting-and-limits.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Value formatting (currency, percentages, custom formats)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Using the format API","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Slider limits and restricted ranges","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Handle locking (start/end fixed)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Min/max bounds per handle","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Edge cases and constraint handling","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Styling and Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/styling.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-styling.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS selectors for track, handle, limits, ticks, buttons","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customizing track color and height","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Handle styling (color, border, size)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Theme integration and built-in themes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS variable customization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Advanced styling patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 and Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WAI-ARIA attributes and roles (","type":"text"},{"text":"role=\"slider\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"aria-valuemin","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"aria-valuemax","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"aria-valuenow","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"aria-orientation","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation (Arrow keys, Home, End, Page Up/Down)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support and ","type":"text"},{"text":"aria-live","type":"text","marks":[{"type":"code_inline"}]},{"text":" regions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Focus management and color contrast requirements","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mobile touch accessibility","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Color Range","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/color-range.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-color-range.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]},{"text":" property and ","type":"text"},{"text":"ColorRangeDataModel","type":"text","marks":[{"type":"code_inline"}]},{"text":" interface","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Three-zone and multi-zone patterns (red/amber/green)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Color range with ","type":"text"},{"text":"Range","type":"text","marks":[{"type":"code_inline"}]},{"text":" type (dual handles)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dynamic color zones based on runtime data","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Real-world: battery, risk, performance, score patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Combining ","type":"text"},{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]},{"text":" with ","type":"text"},{"text":"limits","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ticks","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"tooltip","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Events and Methods","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/events-and-methods.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-events-and-methods.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":" event — continuous value updates while dragging","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":" event — final committed value on drag release","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":" event — post-render initialization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"renderingTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":" — customize tick label text per tick","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"renderedTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":" — post-process tick DOM after all ticks render","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tooltipChange","type":"text","marks":[{"type":"code_inline"}]},{"text":" — customize tooltip display text","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reposition()","type":"text","marks":[{"type":"code_inline"}]},{"text":" method — when and how to call","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"destroy()","type":"text","marks":[{"type":"code_inline"}]},{"text":" method — cleanup and removal","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"React ","type":"text"},{"text":"ref","type":"text","marks":[{"type":"code_inline"}]},{"text":" patterns for programmatic control","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Common patterns: API sync, conditional logic, live preview","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-api-reference.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All official ","type":"text"},{"text":"SliderComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" properties: ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"type","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"min","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"max","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"step","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"orientation","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"ticks","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tooltip","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"limits","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"customValues","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showButtons","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableAnimation","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"width","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableHtmlSanitizer","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"locale","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Official methods: ","type":"text"},{"text":"reposition()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroy()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All official events with correct argument interfaces: ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"renderingTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"renderedTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tooltipChange","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"TicksDataModel","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"placement","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"'Before'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'After'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'Both'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'None'","type":"text","marks":[{"type":"code_inline"}]},{"text":"), ","type":"text"},{"text":"largeStep","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"smallStep","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showSmallTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"format","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"TooltipDataModel","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"isVisible","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"placement","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showOn","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"'Always'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'Focus'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'Click'","type":"text","marks":[{"type":"code_inline"}]},{"text":"), ","type":"text"},{"text":"format","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"LimitDataModel","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"minStart","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"minEnd","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"maxStart","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"maxEnd","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"startHandleFixed","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"endHandleFixed","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"ColorRangeDataModel","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"color","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"start","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"end","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"SliderChangeEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"previousValue","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"action","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"isInteracted","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"text","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"SliderTickEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"text","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tickElement","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"SliderTickRenderedEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"ticksWrapper","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tickElements","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Interface: ","type":"text"},{"text":"SliderTooltipEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"text","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enum: ","type":"text"},{"text":"SliderType","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"'Default'","type":"text","marks":[{"type":"code_inline"}]},{"text":" | ","type":"text"},{"text":"'MinRange'","type":"text","marks":[{"type":"code_inline"}]},{"text":" | ","type":"text"},{"text":"'Range'","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enum: ","type":"text"},{"text":"SliderOrientation","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"'Horizontal'","type":"text","marks":[{"type":"code_inline"}]},{"text":" | ","type":"text"},{"text":"'Vertical'","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Basic Single Value Slider","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import React from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n\nfunction App() {\n return (\n \u003cdiv>\n \u003cSliderComponent \n id=\"slider\" \n value={30}\n min={0}\n max={100}\n />\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Range Slider (Two Handles)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import React from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n\nfunction App() {\n const [range, setRange] = React.useState([30, 70]);\n\n return (\n \u003cdiv>\n \u003cSliderComponent \n id=\"range-slider\" \n type=\"Range\"\n value={range}\n change={(e) => setRange(e.value)}\n min={0}\n max={100}\n />\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Price Range Selector","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import React from 'react';\nimport { SliderComponent } from '@syncfusion/ej2-react-inputs';\nimport '@syncfusion/ej2-react-inputs/styles/material.css';\n\nfunction PriceRangeSelector() {\n const [priceRange, setPriceRange] = React.useState([100, 500]);\n \n const tooltip = {\n placement: 'Before',\n isVisible: true,\n format: 'C2' // Currency format\n };\n\n return (\n \u003cdiv>\n \u003ch3>Price Range: ${priceRange[0]} - ${priceRange[1]}\u003c/h3>\n \u003cSliderComponent \n id=\"price-slider\"\n type=\"Range\"\n value={priceRange}\n change={(e) => setPriceRange(e.value)}\n min={0}\n max={1000}\n step={10}\n tooltip={tooltip}\n />\n \u003c/div>\n );\n}\nexport default PriceRangeSelector;","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 1: Single Value with Ticks","type":"text"}]},{"type":"paragraph","content":[{"text":"Use Default type for simple numeric selection with visual scale.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"default-slider\"\n value={40}\n min={0}\n max={100}\n step={5}\n ticks={{\n placement: 'After',\n largeStep: 20,\n smallStep: 5,\n showSmallTicks: true\n }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 2: Range with Fixed Limits","type":"text"}]},{"type":"paragraph","content":[{"text":"Use Range type with limits to restrict handle movement to specific areas.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"limited-range\"\n type=\"Range\"\n value={[25, 75]}\n limits={{\n enabled: true,\n minStart: 10,\n minEnd: 40,\n maxStart: 60,\n maxEnd: 90\n }}\n tooltip={{ isVisible: true }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 3: Formatted Values (Currency)","type":"text"}]},{"type":"paragraph","content":[{"text":"Display values as currency using format API.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"currency-slider\"\n type=\"Range\"\n value={[1000, 5000]}\n min={0}\n max={10000}\n step={100}\n tooltip={{\n isVisible: true,\n format: 'C0' // Currency without decimals\n }}\n ticks={{\n placement: 'After',\n largeStep: 2000,\n format: 'C0'\n }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 4: Vertical Orientation","type":"text"}]},{"type":"paragraph","content":[{"text":"Display slider vertically for space-constrained layouts.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cdiv style={{ height: '300px', width: '100px' }}>\n \u003cSliderComponent\n id=\"vertical-slider\"\n value={50}\n orientation=\"Vertical\"\n tooltip={{ isVisible: true }}\n />\n\u003c/div>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 5: With Increment/Decrement Buttons","type":"text"}]},{"type":"paragraph","content":[{"text":"Add buttons to manually adjust slider values.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"button-slider\"\n type=\"Range\"\n value={[30, 70]}\n showButtons={true}\n tooltip={{ isVisible: true }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 6: Color Range (Zones)","type":"text"}]},{"type":"paragraph","content":[{"text":"Paint distinct color sections on the slider track using ","type":"text"},{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { ColorRangeDataModel } from '@syncfusion/ej2-react-inputs';\n\nconst colorRange: ColorRangeDataModel[] = [\n { color: '#ff4040', start: 0, end: 33 }, // Low zone — red\n { color: '#ffb300', start: 34, end: 66 }, // Mid zone — amber\n { color: '#00c853', start: 67, end: 100 } // High zone — green\n];\n\n\u003cSliderComponent\n id=\"color-slider\"\n type=\"MinRange\"\n value={50}\n colorRange={colorRange}\n tooltip={{ isVisible: true, showOn: 'Always' }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 7: Custom Value Scale","type":"text"}]},{"type":"paragraph","content":[{"text":"Use non-numeric labels as slider values with ","type":"text"},{"text":"customValues","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"size-slider\"\n customValues={['XS', 'S', 'M', 'L', 'XL', 'XXL']}\n value=\"M\"\n tooltip={{ isVisible: true }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Pattern 8: Read-Only Display","type":"text"}]},{"type":"paragraph","content":[{"text":"Show a locked slider for informational display.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cSliderComponent\n id=\"status-slider\"\n type=\"MinRange\"\n value={65}\n min={0}\n max={100}\n readonly={true}\n tooltip={{ isVisible: true, showOn: 'Always' }}\n ticks={{ placement: 'After', largeStep: 20 }}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Properties","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number | number[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"null","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Single value or ","type":"text"},{"text":"[start, end]","type":"text","marks":[{"type":"code_inline"}]},{"text":" array for Range type","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"type","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Default' | 'MinRange' | 'Range'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Default'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slider mode","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"min","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Minimum selectable value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"100","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maximum selectable value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"step","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Value increment/decrement per step","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"orientation","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Horizontal' | 'Vertical'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Horizontal'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slider direction","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tooltip","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"TooltipDataModel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{ isVisible: false }","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tooltip configuration","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ticks","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"TicksDataModel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{ placement: 'before' }","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tick marks configuration","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"limits","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LimitDataModel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{ enabled: false }","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Thumb movement restrictions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ColorRangeDataModel[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Color zones on the track","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"customValues","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string[] | number[]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"null","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom value scale (ignores min/max/step)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showButtons","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show +/- increment/decrement buttons","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable or disable the slider","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read-only display mode","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right-to-left layout","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"width","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number | string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"null","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slider element width","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom CSS classes on root element","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Type Comparison","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Handles","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fill Behavior","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Case","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No fill","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Simple numeric selection","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MinRange","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fill from min","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visual progress/level indicator","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Range","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fill between handles","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Min/max range selection","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Use Cases","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Budget Range Selector","type":"text"}]},{"type":"paragraph","content":[{"text":"Select min and max budget with step increments and currency formatting. → Use ","type":"text"},{"text":"type=\"Range\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"step={50}","type":"text","marks":[{"type":"code_inline"}]},{"text":", format ","type":"text"},{"text":"'C0'","type":"text","marks":[{"type":"code_inline"}]},{"text":", tooltip enabled","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Time Range Picker","type":"text"}]},{"type":"paragraph","content":[{"text":"Select time window (hours, minutes, days). → Use ","type":"text"},{"text":"type=\"Range\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", custom formatting via ","type":"text"},{"text":"renderingTicks","type":"text","marks":[{"type":"code_inline"}]},{"text":" event","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Volume/Brightness Control","type":"text"}]},{"type":"paragraph","content":[{"text":"Single handle adjustment with immediate feedback. → Use ","type":"text"},{"text":"type=\"Default\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", no ticks, always-visible tooltip","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Score/Rating Range","type":"text"}]},{"type":"paragraph","content":[{"text":"MinRange mode with shadow showing current level. → Use ","type":"text"},{"text":"type=\"MinRange\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"min={0}","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"max={10}","type":"text","marks":[{"type":"code_inline"}]},{"text":", step-based","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Product Filter","type":"text"}]},{"type":"paragraph","content":[{"text":"Multiple product categories with price ranges. → Use ","type":"text"},{"text":"type=\"Range\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", limits for each category, event handlers","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Events","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Event","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Trigger","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Usage","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Component created and rendered","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"One-time setup operations","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"change","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Value changing while dragging","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Real-time feedback (continuous)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"changed","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Drag complete (thumb released)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Capture final committed value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tooltipChange","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tooltip about to render","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom tooltip text formatting","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"renderingTicks","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Each tick being rendered","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom tick label text","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"renderedTicks","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"All ticks rendered","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Post-process tick DOM elements","type":"text"}]}]}]}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"⚠️ Note:","type":"text","marks":[{"type":"strong"}]},{"text":" The official event for continuous updates while dragging is ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", not ","type":"text"},{"text":"changing","type":"text","marks":[{"type":"code_inline"}]},{"text":". The event fired after drag completes is ","type":"text"},{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":". Do NOT use ","type":"text"},{"text":"onChange","type":"text","marks":[{"type":"code_inline"}]},{"text":" prop (that is a React native input prop). Use ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":" directly.","type":"text"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Troubleshooting Quick Links","type":"text"}]},{"type":"paragraph","content":[{"text":"Component not displaying?","type":"text","marks":[{"type":"strong"}]},{"text":" → Check CSS imports and theme in ","type":"text"},{"text":"getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-getting-started.md","title":null}}]}]},{"type":"paragraph","content":[{"text":"Values not updating?","type":"text","marks":[{"type":"strong"}]},{"text":" → Use ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":" (continuous) or ","type":"text"},{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":" (on release) events — NOT ","type":"text"},{"text":"onChange","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"paragraph","content":[{"text":"Formatting not working?","type":"text","marks":[{"type":"strong"}]},{"text":" → See format API examples in ","type":"text"},{"text":"formatting-and-limits.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-formatting-and-limits.md","title":null}}]}]},{"type":"paragraph","content":[{"text":"Accessibility issues?","type":"text","marks":[{"type":"strong"}]},{"text":" → Refer to ","type":"text"},{"text":"accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-accessibility.md","title":null}}]},{"text":" for ARIA and keyboard support","type":"text"}]},{"type":"paragraph","content":[{"text":"Vertical slider not rendering?","type":"text","marks":[{"type":"strong"}]},{"text":" → Wrap in a container with explicit ","type":"text"},{"text":"height","type":"text","marks":[{"type":"code_inline"}]},{"text":" (e.g., ","type":"text"},{"text":"style={{ height: '300px' }}","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"paragraph","content":[{"text":"Range type with single value?","type":"text","marks":[{"type":"strong"}]},{"text":" → Always pass ","type":"text"},{"text":"value={[start, end]}","type":"text","marks":[{"type":"code_inline"}]},{"text":" array for ","type":"text"},{"text":"type=\"Range\"","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"paragraph","content":[{"text":"Color zones not showing?","type":"text","marks":[{"type":"strong"}]},{"text":" → Check ","type":"text"},{"text":"colorRange","type":"text","marks":[{"type":"code_inline"}]},{"text":" array has valid ","type":"text"},{"text":"start","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"end","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"color","type":"text","marks":[{"type":"code_inline"}]},{"text":" properties","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Next Steps","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Choose your slider type based on use case (","type":"text"},{"text":"Default","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"MinRange","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"Range","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":"getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-getting-started.md","title":null}}]},{"text":" for installation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Navigate to specific reference for your feature needs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test with examples from reference files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Customize styling using ","type":"text"},{"text":"styling.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-styling.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ensure accessibility following ","type":"text"},{"text":"accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-accessibility.md","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verify all API usage against ","type":"text"},{"text":"api-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-api-reference.md","title":null}}]}]}]}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"⚠️ Critical:","type":"text","marks":[{"type":"strong"}]},{"text":" Only use APIs explicitly listed in ","type":"text"},{"text":"references/api-reference.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/range-slider-api-reference.md","title":null}}]},{"text":". Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" reference ","type":"text"},{"text":"onChange","type":"text","marks":[{"type":"code_inline"}]},{"text":" (use ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"changed","type":"text","marks":[{"type":"code_inline"}]},{"text":"), ","type":"text"},{"text":"toggle()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"open()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"close()","type":"text","marks":[{"type":"code_inline"}]},{"text":", or any undocumented methods.","type":"text"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"ColorPicker","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ColorPicker lets users pick colors via a visual picker (HSV + opacity) or a palette of swatches. It renders as a SplitButton by default (opens a popup) or inline, and supports RGB, HSV, and Hex color formats.","type":"text"}]},{"type":"paragraph","content":[{"text":"Package:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"type":"br"},{"text":"Component:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"\u003cColorPickerComponent>","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation with Vite or Create React App","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"npm package setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal working example","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the application","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Modes and Color Value","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/modes-and-value.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-modes-and-value.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Inline rendering vs popup (SplitButton)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Picker mode vs Palette mode","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting initial color value (hex codes)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Opacity support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rendering palette alone (locking mode)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Palette Features","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/palette-features.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-palette-features.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom color palettes (","type":"text"},{"text":"presetColors","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom palette tile rendering (","type":"text"},{"text":"beforeTileRender","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No-color / clear color support (","type":"text"},{"text":"noColor","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom no-color option","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recent colors display (","type":"text"},{"text":"showRecentColors","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Palette column count (","type":"text"},{"text":"columns","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"UI Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/ui-customization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-ui-customization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hide the input value area","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom picker handle","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom primary button with icon","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Display hex code in input element","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hide control buttons (Apply/Cancel)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS class overrides and Theme Studio","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Excel-like custom UI with SplitButton and Dialog","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Integration and Advanced","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/integration-and-advanced.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-integration-and-advanced.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Embedding ColorPicker in a DropDownButton","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Popup toggle control","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"State persistence across page reloads","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mode switcher visibility and events","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabled state","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Localization and RTL","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/localization-and-rtl.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-localization-and-rtl.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Localizing Apply / Cancel / ModeSwitcher labels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Loading translation objects with ","type":"text"},{"text":"L10n","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Right-to-left rendering (","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 / Section 508 compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WAI-ARIA attributes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation shortcuts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Accessibility validation","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/colorpicker-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties with types and defaults","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All methods with signatures","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All events with payload types","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"npm install @syncfusion/ej2-react-inputs --save","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"css"},"content":[{"text":"/* src/App.css */\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind3.css\";","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { ColorPickerComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cdiv id=\"container\">\n \u003cdiv className=\"wrap\">\n \u003ch4>Choose Color\u003c/h4>\n \u003cColorPickerComponent id=\"color-picker\" />\n \u003c/div>\n \u003c/div>\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Inline picker (no popup)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cColorPickerComponent inline={true} showButtons={false} />","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Palette-only mode","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cColorPickerComponent mode=\"Palette\" modeSwitcher={false} showButtons={false} />","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Set initial color + handle changes","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';\n\nfunction App() {\n function onChange(args: ColorPickerEventArgs): void {\n console.log(args.currentValue.hex); // e.g. \"#ff5733\"\n console.log(args.currentValue.rgba); // e.g. \"rgba(255,87,51,1)\"\n }\n return \u003cColorPickerComponent value=\"#ff5733\" change={onChange} />;\n}","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Custom palette with preset colors","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"const presets: { [key: string]: string[] } = {\n 'brand': ['#0078d4', '#106ebe', '#005a9e', '#004578'],\n 'accents': ['#e81123', '#ff8c00', '#00b294', '#68217a']\n};\n\n\u003cColorPickerComponent\n mode=\"Palette\"\n presetColors={presets}\n columns={4}\n modeSwitcher={false}\n inline={true}\n showButtons={false}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Disable opacity slider","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cColorPickerComponent enableOpacity={false} />","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"No-color support (clear selection)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cColorPickerComponent\n mode=\"Palette\"\n noColor={true}\n modeSwitcher={false}\n showButtons={false}\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Localization (German)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { L10n } from '@syncfusion/ej2-base';\n\nL10n.load({\n 'de-DE': {\n 'colorpicker': { Apply: 'Anwenden', Cancel: 'Abbrechen', ModeSwitcher: 'Modus wechseln' }\n }\n});\n\n\u003cColorPickerComponent locale=\"de-DE\" />","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Props","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prop","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'#008000ff'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Initial color (3/4/6/8 digit hex)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mode","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Picker' | 'Palette'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"'Picker'","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Which panel to show initially","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"inline","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Render component directly (no popup)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showButtons","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show Apply/Cancel buttons","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"modeSwitcher","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show mode switcher button","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"noColor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add a \"no color\" tile to palette","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"presetColors","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"null","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom color groups for palette","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"columns","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Palette columns count","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableOpacity","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show opacity slider","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showRecentColors","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show recent color tiles (palette only)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Disable the component","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom CSS class on root element","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right-to-left rendering","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"locale","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Locale string for localization","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"MaskedTextBox","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React MaskedTextBox component enforces a specific input format by applying a mask pattern, guiding users to enter data in the correct structure. It is ideal for phone numbers, postal codes, dates, IP addresses, product keys, and any scenario where input must follow a predefined format.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installation via npm (","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Vite / Create-React-App setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS imports for theming","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rendering a basic MaskedTextBox","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting the ","type":"text"},{"text":"mask","type":"text","marks":[{"type":"code_inline"}]},{"text":" property for format enforcement","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Mask Configuration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/mask-configuration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-mask-configuration.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standard mask element tokens (0, 9, #, L, ?, &, C, A, a, \u003c, >, |, )","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom characters via ","type":"text"},{"text":"customCharacters","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Regular expression masks for flexible patterns (e.g., IP addresses)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prompt character customization via ","type":"text"},{"text":"promptChar","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Adornments (Prepend / Append Elements)","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/adornments.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-adornments.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Adding icons or buttons before/after the input with ","type":"text"},{"text":"prependTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"appendTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Entry guidance, quick actions, and context labels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Class and functional component examples","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"React Hooks Integration","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/react-hooks.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-react-hooks.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Controlled component with ","type":"text"},{"text":"useState","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Auto-focus on mount using ","type":"text"},{"text":"useEffect","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"useRef","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"focusIn()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multiple masked inputs with ","type":"text"},{"text":"useReducer","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Handling the ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":" event in functional components","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Style, Appearance & Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/style-and-customization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-style-and-customization.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom styling with ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS overrides for wrapper, hover, and focus states","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting cursor position on focus using the ","type":"text"},{"text":"focus","type":"text","marks":[{"type":"code_inline"}]},{"text":" event (","type":"text"},{"text":"selectionStart","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"selectionEnd","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Displaying numeric keypad on mobile with ","type":"text"},{"text":"type=\"tel\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]},{"text":" options (Never, Always, Auto)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Form Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/form-validation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-form-validation.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integrating with Syncfusion ","type":"text"},{"text":"FormValidator","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Defining custom validation rules using ","type":"text"},{"text":"ej2_instances","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom error placement with ","type":"text"},{"text":"customPlacement","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Checking for incomplete masked values using ","type":"text"},{"text":"promptChar","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/maskedtextbox-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties: ","type":"text"},{"text":"mask","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"placeholder","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"floatLabelType","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"promptChar","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"customCharacters","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"showClearButton","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"enablePersistence","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"htmlAttributes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"locale","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"width","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"prependTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"appendTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Methods: ","type":"text"},{"text":"focusIn()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focusOut()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getMaskedValue()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroy()","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"getPersistData()","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Events: ","type":"text"},{"text":"change","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"focus","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"blur","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"destroyed","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import * as React from 'react';\nimport { MaskedTextBoxComponent } from '@syncfusion/ej2-react-inputs';\nimport '../node_modules/@syncfusion/ej2-base/styles/tailwind3.css';\nimport '../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css';\n\nexport default function App() {\n return (\n \u003cMaskedTextBoxComponent\n mask=\"000-000-0000\"\n placeholder=\"Enter phone number\"\n floatLabelType=\"Auto\"\n />\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Phone Number Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cMaskedTextBoxComponent mask=\"000-000-0000\" placeholder=\"Phone\" floatLabelType=\"Always\" />","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"IP Address with Regex Mask","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"\u003cMaskedTextBoxComponent\n mask=\"[0-2][0-9][0-9].[0-2][0-9][0-9].[0-2][0-9][0-9].[0-2][0-9][0-9]\"\n placeholder=\"IP Address (ex: 212.212.111.222)\"\n floatLabelType=\"Always\"\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Custom AM/PM Time Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"const chars = { P: 'P,A,p,a', M: 'M,m' };\n\u003cMaskedTextBoxComponent\n mask=\"00:00 >PM\"\n customCharacters={chars}\n placeholder=\"Time (ex: 10:00 PM)\"\n floatLabelType=\"Always\"\n/>","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Read Masked Value Programmatically","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"const maskRef = React.useRef(null);\n// Later:\nconst maskedVal = maskRef.current.getMaskedValue(); // e.g., \"123-456-7890\"\nconst rawVal = maskRef.current.value; // e.g., \"1234567890\"","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Controlled Input with Change Event","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"const [phone, setPhone] = React.useState('');\n\u003cMaskedTextBoxComponent\n mask=\"000-000-0000\"\n value={phone}\n change={(e) => setPhone(e.value)}\n placeholder=\"Phone\"\n floatLabelType=\"Auto\"\n/>","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Rating","type":"text"}]},{"type":"paragraph","content":[{"text":"The Syncfusion React ","type":"text"},{"text":"RatingComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" lets users select a rating value from a set of visual symbols (stars by default). It supports ","type":"text"},{"text":"precision modes","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"custom templates","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"tooltips","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"labels","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"reset","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"read-only/disabled","type":"text","marks":[{"type":"strong"}]},{"text":" states, full ","type":"text"},{"text":"accessibility","type":"text","marks":[{"type":"strong"}]},{"text":" compliance, and rich CSS customization.","type":"text"}]},{"type":"paragraph","content":[{"text":"Package:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Navigation Guide","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Getting Started","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/getting-started.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-getting-started.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Installing ","type":"text"},{"text":"@syncfusion/ej2-react-inputs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS theme imports for Tailwind3","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimal ","type":"text"},{"text":"RatingComponent","type":"text","marks":[{"type":"code_inline"}]},{"text":" setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting the initial ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]},{"text":" property","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Running the Vite/React app","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Selection and Reset","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/selection.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-selection.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting a rating value with ","type":"text"},{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimum rating value with ","type":"text"},{"text":"min","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Single-selection mode with ","type":"text"},{"text":"enableSingleSelection","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Show/hide reset button with ","type":"text"},{"text":"allowReset","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Programmatic ","type":"text"},{"text":"reset()","type":"text","marks":[{"type":"code_inline"}]},{"text":" method","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Precision Modes","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/precision-modes.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-precision-modes.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PrecisionType.Full","type":"text","marks":[{"type":"code_inline"}]},{"text":" — whole number increments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PrecisionType.Half","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 0.5 increments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PrecisionType.Quarter","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 0.25 increments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PrecisionType.Exact","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 0.1 increments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Combining precision with initial value","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Appearance and Customization","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/appearance.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-appearance.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Controlling item count with ","type":"text"},{"text":"itemsCount","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Disabling the component with ","type":"text"},{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hiding/showing the component with ","type":"text"},{"text":"visible","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read-only mode with ","type":"text"},{"text":"readOnly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CSS customization with ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]},{"text":" (border color, fill color, item spacing, icon)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Changing rating icon via CSS","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Labels","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/labels.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-labels.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Showing the current value label with ","type":"text"},{"text":"showLabel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"labelPosition","type":"text","marks":[{"type":"code_inline"}]},{"text":" options: Top, Bottom, Left, Right","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom label content with ","type":"text"},{"text":"labelTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Tooltip","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/tooltip.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-tooltip.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling tooltips with ","type":"text"},{"text":"showTooltip","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom tooltip content with ","type":"text"},{"text":"tooltipTemplate","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tooltip appearance via ","type":"text"},{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Templates","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/templates.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-templates.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"emptyTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":" for unrated items","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"fullTemplate","type":"text","marks":[{"type":"code_inline"}]},{"text":" for rated items","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Emoji rating symbols","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"SVG icon rating symbols","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PNG image rating symbols","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Precision support in templates via ","type":"text"},{"text":"--rating-value","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Events","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/events.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-events.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"beforeItemRender","type":"text","marks":[{"type":"code_inline"}]},{"text":" — customize items before render","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"created","type":"text","marks":[{"type":"code_inline"}]},{"text":" — after component initialization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"onItemHover","type":"text","marks":[{"type":"code_inline"}]},{"text":" — track hovered items","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"valueChanged","type":"text","marks":[{"type":"code_inline"}]},{"text":" — react to user rating changes","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Accessibility","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/accessibility.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-accessibility.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WCAG 2.2 / Section 508 / ADA compliance","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WAI-ARIA attributes (","type":"text"},{"text":"role=slider","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"aria-valuemin/max/now","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keyboard navigation shortcuts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RTL support with ","type":"text"},{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screen reader support","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"API Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"📄 ","type":"text"},{"text":"Read:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"references/api.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/rating-api.md","title":null}}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All properties, methods, and events with types and defaults","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RatingItemEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"RatingHoverEventArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"RatingChangedEventArgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"LabelPosition","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"PrecisionType","type":"text","marks":[{"type":"code_inline"}]},{"text":" enums","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quick Start","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"npm install @syncfusion/ej2-react-inputs --save","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"css"},"content":[{"text":"/* src/App.css */\n@import \"../node_modules/@syncfusion/ej2-base/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-react-inputs/styles/tailwind3.css\";\n@import \"../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css\";","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\nimport './App.css';\n\nfunction App() {\n return (\n \u003cRatingComponent id=\"rating\" value={3} />\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Rating with value change handler","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { RatingComponent, RatingChangedEventArgs } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n const [rating, setRating] = React.useState(3);\n\n const handleValueChanged = (args: RatingChangedEventArgs) => {\n setRating(args.value);\n };\n\n return (\n \u003cRatingComponent\n id=\"rating\"\n value={rating}\n valueChanged={handleValueChanged}\n />\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Half-precision rating with label","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { RatingComponent, PrecisionType } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cRatingComponent\n id=\"rating\"\n value={3.5}\n precision={PrecisionType.Half}\n showLabel={true}\n />\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Read-only rating (display only)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cRatingComponent id=\"rating\" value={4} readOnly={true} showTooltip={false} />\n );\n}\nexport default App;","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Rating with reset button","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"import { RatingComponent } from '@syncfusion/ej2-react-inputs';\nimport * as React from 'react';\n\nfunction App() {\n return (\n \u003cRatingComponent id=\"rating\" value={3} allowReset={true} />\n );\n}\nexport default App;","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Key Props at a Glance","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prop","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"value","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Current rating value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"itemsCount","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Number of rating items","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"min","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"number","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Minimum selectable value","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"precision","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PrecisionType | string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Rating granularity","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"allowReset","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show reset button","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readOnly","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prevent user interaction","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Disable the component","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"visible","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show/hide the component","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showLabel","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show current value label","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"labelPosition","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LabelPosition | string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Label placement","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"showTooltip","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show hover tooltips","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableSingleSelection","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Only one item selected","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableAnimation","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hover animation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableRtl","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"boolean","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"false","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Right-to-left mode","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cssClass","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"''","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom CSS class","type":"text"}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"syncfusion-react-inputs","author":"@skillopedia","source":{"stars":3,"repo_name":"react-ui-components-skills","origin_url":"https://github.com/syncfusion/react-ui-components-skills/blob/HEAD/skills/syncfusion-react-inputs/SKILL.md","repo_owner":"syncfusion","body_sha256":"efa1392992b043ee046bdf921b829e1129d10f34d3eeb61aa96af4dd6abb77ba","cluster_key":"56e07fd60269d8703e4c913b70213b649fa758e00b2779356ba8cbf3d7d9bfac","clean_bundle":{"format":"clean-skill-bundle-v1","source":"syncfusion/react-ui-components-skills/skills/syncfusion-react-inputs/SKILL.md","text_bytes":812507,"source_commit":"4baa652dcd2a01ebb3cf9ca66051cc18ffa40f81","skills_sh_rank":16315,"attachment_count":94,"text_attachments":94,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/syncfusion-react-inputs/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"web-development","category_label":"Web"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"web-development","metadata":{"author":"Syncfusion Inc","version":"34.1.29","category":"Inputs"},"import_tag":"skills-sh-top20k-2026-11","description":"Comprehensive guide for implementing Syncfusion React input components including Uploader, NumericTextBox, TextBox, TextArea, CheckBox, OTP Input, Signature, RangeSlider, ColorPicker, MaskedTextBox, and Rating. Use this when building file upload UIs with async/chunk uploads, drag-and-drop functionality, numeric inputs with validation and formatting, text inputs with floating labels, custom adornments, form integration, accessibility compliance, and styling in React applications."}},"renderedAt":1793671200855}

Implementing Syncfusion React Inputs Uploader The Syncfusion React UploaderComponent provides a rich file upload control with async upload, drag-and-drop, chunk upload with pause/resume/cancel, validation, templates, form integration, and accessibility support. Navigation Guide 🛑 Agentic use: Do not execute multiple steps autonomously. Confirm with the user before each action (install, run, file creation). Getting Started 📄 Read: references/getting-started.md - Installing 🛑 STOP — Do not install packages autonomously. Ask the user to run: . Verify with - License registration - Basic usage…