A Power Apps Component Framework (PCF) control that provides dynamic filtering for dependent choice/option set fields in Dynamics 365 and Power Apps. Built with React 16.14 and Fluent UI v9.
- Dynamic Filtering: Automatically filters dependent choice options based on parent choice selection
- Flexible Configuration: JSON-based mapping configuration for easy customization
- Multi-Select Support: Works with both single-select and multi-select option sets
- Fluent UI Integration: Modern UI with theme support and accessibility
- Metadata Service: WebAPI-based metadata retrieval with 5-minute caching
- Auto-Cleanup: Automatically removes invalid selections when parent changes
- Configuration Validation: Validates JSON configuration on load with user-friendly error dialog
- Multi-Language Support: Fully localized in 14 languages
- TypeScript: Fully typed for better development experience
- Performance Optimized: Uses React hooks and memoization for efficient rendering
The control is fully localized and supports the following languages:
English (1033) - English
Czech (1029) - Čeština
Danish (1030) - Dansk
German (1031) - Deutsch
Greek (1032) - Ελληνικά
French (1036) - Français
Hungarian (1038) - Magyar
Italian (1040) - Italiano
Japanese (1041) - 日本語
Korean (1042) - 한국어
Polish (1045) - Polski
Russian (1049) - Русский
Slovak (1051) - Slovenčina
Swedish (1053) - Svenska
Ukrainian (1058) - Українська
Vietnamese (1066) - Tiếng Việt
Portuguese - Portugal (2070) - Português
Spanish - Spain (3082) - Español
The control automatically displays in the user's language based on their Dynamics 365/Power Apps language settings.
Perfect for scenarios like:
- Geographic Relationships: Continent → Country → State → City
- Product Hierarchies: Category → Subcategory → Product
- Organizational Structures: Department → Team → Role
- Classification Systems: Industry → Sector → Subsector
- Node.js (v14 or higher)
- npm or yarn
- Power Apps CLI (
pac) - Visual Studio Code (recommended)
-
Clone the repository
git clone https://github.com/aidevme/dependent-choice.git cd dependent-choice -
Install dependencies
npm install
-
Build the control
npm run build
-
Run in watch mode (for development)
npm start watch
The control defines three properties in ControlManifest.Input.xml:
-
dependentChoice (Required, Bound)
- The dependent choice field that will be filtered
- Supports:
OptionSetandMultiSelectOptionSet
-
parentChoice (Required, Bound)
- The parent choice field that drives the filtering
- Supports:
OptionSetandMultiSelectOptionSet
-
configurationParameters (Input)
- JSON configuration for mapping parent-to-dependent values
- Type: Multiple (multi-line text)
The configurationParameters property expects a JSON string with the following structure:
{
"mappings": [
{
"parentValue": 1,
"dependentValues": [100, 101, 102, 103]
},
{
"parentValue": 2,
"dependentValues": [200, 201, 202]
},
{
"parentValue": 3,
"dependentValues": []
}
]
}Important: The JSON must be minified (single line) when entering into Power Apps.
The repository includes a complete example in DependentChoice/statics/configurationParameters.json that maps 7 continents to 195 countries:
{
"mappings": [
{
"parentValue": 1,
"dependentValues": [100000002, 100000004, 100000018, ...]
},
{
"parentValue": 2,
"dependentValues": []
}
]
}To use this configuration, minify the JSON:
# Use any JSON minifier or paste into Power Apps as a single line
{"mappings":[{"parentValue":1,"dependentValues":[100000002,100000004,...]},{"parentValue":2,"dependentValues":[]}]}-
Build the solution
npm run build
-
Create solution package
cd Solution/DependentChoiceSolution msbuild /t:restore msbuild /p:Configuration=Release -
Import to Dataverse
- Navigate to your Power Apps environment
- Go to Solutions → Import
- Select the generated
.zipfile fromSolution/DependentChoiceSolution/bin/Release
# Authenticate
pac auth create --url https://your-org.crm.dynamics.com
# Push control
pac pcf push --publisher-prefix aidevme- Open your Dataverse table form in the form designer
- Add the parent choice field (e.g., Continent)
- Add the dependent choice field (e.g., Country)
- Select the dependent choice field
- Click + Component in the properties panel
- Select DependentChoice from the list
- Configure the properties:
- dependentChoice: Bind to your dependent field (e.g., Country)
- parentChoice: Bind to your parent field (e.g., Continent)
- configurationParameters: Paste your minified JSON configuration
- Save and publish the form
- Open a record
- Select a value in the parent choice field
- Observe the dependent choice field automatically filter
dependent-choice/
├── DependentChoice/ # Main control directory
│ ├── components/
│ │ ├── DependentChoice.tsx # Main React component
│ │ └── DependentChoiceConfigurationErrorDialog.tsx # Error dialog component
│ ├── generated/
│ │ └── ManifestTypes.d.ts # Auto-generated TypeScript types
│ ├── hooks/
│ │ └── useTranslation.ts # Translation hook for components
│ ├── services/
│ │ ├── index.ts # Service exports
│ │ ├── DependencyMappingService/
│ │ │ └── DependencyMappingService.ts # Filtering logic
│ │ ├── MetadataService/
│ │ │ └── MetadataService.ts # Dataverse metadata retrieval
│ │ └── PcfContextService/
│ │ ├── PcfContext.tsx # React context provider
│ │ └── PcfContextService.ts # PCF context wrapper
│ ├── statics/
│ │ ├── configurationParameters.json # Example configuration
│ ├── strings/ # Localization files (18 languages)
│ │ ├── DependentChoice.1029.resx # Czech
│ │ ├── DependentChoice.1030.resx # Danish
│ │ ├── DependentChoice.1031.resx # German
│ │ ├── DependentChoice.1032.resx # Greek
│ │ ├── DependentChoice.1033.resx # English
│ │ ├── DependentChoice.1036.resx # French
│ │ ├── DependentChoice.1038.resx # Hungarian
│ │ ├── DependentChoice.1040.resx # Italian
│ │ ├── DependentChoice.1041.resx # Japanese
│ │ ├── DependentChoice.1042.resx # Korean
│ │ ├── DependentChoice.1045.resx # Polish
│ │ ├── DependentChoice.1049.resx # Russian
│ │ ├── DependentChoice.1051.resx # Slovak
│ │ ├── DependentChoice.1053.resx # Swedish
│ │ ├── DependentChoice.1058.resx # Ukrainian
│ │ ├── DependentChoice.1066.resx # Vietnamese
│ │ ├── DependentChoice.2070.resx # Portuguese (Portugal)
│ │ └── DependentChoice.3082.resx # Spanish (Spain)
│ ├── styles/
│ │ └── Styles.ts # Fluent UI styles & hooks
│ ├── tools/
│ │ ├── ConfigurationValidator.ts # JSON configuration validator
│ │ └── index.ts # Tool exports
│ ├── ControlManifest.Input.xml # PCF manifest
│ ├── DependentChoice.pcfproj # MSBuild project file
│ ├── DependentChoiceApp.tsx # React app wrapper
│ └── index.ts # PCF control entry point
├── Solution/ # Dataverse solution
│ └── DependentChoiceSolution/
│ ├── src/ # Solution files
│ │ └── Other/
│ │ ├── Customizations.xml
│ │ ├── Relationships.xml
│ │ └── Solution.xml
│ └── DependentChoiceSolution.cdsproj # CDS solution project
├── docs/ # Documentation
│ ├── api/ # API documentation (TypeDoc)
│ ├── blog/ # Development blog posts
│ └── todos/ # Research & planning docs
├── .github/
│ ├── ISSUE_TEMPLATE/ # GitHub issue templates
│ ├── prompts/ # AI prompts & documentation
│ ├── workflows/ # GitHub Actions CI/CD
│ └── copilot-instructions.md # Development guidelines
├── out/ # Build output directory
├── obj/ # Intermediate build files
├── dependent-choice.pcfproj # Root MSBuild project
├── eslint.config.mjs # ESLint flat configuration
├── featureconfig.json # PCF feature configuration
├── package.json # npm dependencies
├── pcfconfig.json # PCF build configuration
├── tsconfig.json # TypeScript configuration
├── typedoc.json # TypeDoc documentation config
├── CONTRIBUTING.md # Contribution guidelines
├── LICENSE # MIT License
├── README.md # This file
└── SECURITY.md # Security policy
┌─────────────────────────────────────────────────────────────┐
│ PCF Control (index.ts) │
│ ├── Reads parent choice value │
│ ├── Reads configuration parameters │
│ └── Passes props to React app │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DependentChoiceApp.tsx │
│ ├── Creates PcfContextService │
│ │ └── Initializes DependencyMappingService │
│ ├── Provides theme and context to components │
│ └── Renders DependentChoice component │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DependentChoice.tsx │
│ ├── Monitors parent choice value changes │
│ ├── Uses DependencyMappingService to get allowed values │
│ ├── Filters options based on mapping │
│ └── Renders Fluent UI Dropdown with filtered options │
└─────────────────────────────────────────────────────────────┘
- Parent Value Change: User selects a value in the parent choice field
- Get Mapping:
DependencyMappingService.getDependentValues(parentValue)retrieves allowed values - Filter Options: Only options with values in the allowed list are shown
- Special Cases:
- No mapping found → Show all options (fail-safe)
- Empty array mapping → Show no options (explicit restriction)
- Currently selected value → Always kept visible even if not in mapping
# Install ESLint (required by pcf-scripts)
npm installnpm run build- Full build (validates manifest, runs ESLint, compiles TypeScript, bundles)npm run refreshTypes- Regenerate ManifestTypes.d.ts after editing manifestnpm start watch- Development mode with auto-rebuildnpm run lint:fix- Auto-fix ESLint issues
- PascalCase: Components, interfaces, classes (
DependentChoice,IInputs) - camelCase: Variables, functions, properties (
handleChange,parentValue) - TSDoc: All public APIs must be documented
The control includes extensive console logging for troubleshooting:
// Check console for these logs:
"DependencyMappingService: initialize called with:" // Configuration received
"DependencyMappingService: Configuration loaded successfully" // Parsing succeeded
"DependentChoice: Filtering options" // Filter triggered
"DependentChoice: Parent values to check:" // Parent value detected
"DependentChoice: Got dependent values for parent X:" // Allowed values retrieved
"DependentChoice: Filtered options count:" // Final result-
Identify Your Option Values
// Use browser console in Power Apps form // Check the option set values for your fields
-
Create Configuration
{ "mappings": [ { "parentValue": <your_parent_value>, "dependentValues": [<dependent_value_1>, <dependent_value_2>, ...] } ] } -
Minify JSON
- Remove all whitespace and newlines
- Paste as single line into configurationParameters property
-
Test
- Save form
- Test parent-dependent filtering behavior
To add custom features:
- Modify the Component - Edit
DependentChoice/components/DependentChoice.tsx - Add New Services - Create in
DependentChoice/services/ - Update Manifest - Add properties in
ControlManifest.Input.xml - Regenerate Types - Run
npm run refreshTypes - Rebuild - Run
npm run build
Check Console Logs:
- Open browser developer console (F12)
- Look for initialization logs
- Verify configuration is loaded
- Check parent value detection
Common Issues:
- Configuration not provided or malformed JSON
- Parent value doesn't match mapping keys
- Option values don't match mapping values
ESLint Not Found:
npm installType Errors:
npm run refreshTypesCache Issues:
# Clear build artifacts
Remove-Item -Recurse -Force obj, out
npm run buildContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Power Apps Component Framework (PCF)
- UI components from Fluent UI v9
- Country data sourced from public domain
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ for the Power Platform Community


















