The Virtual PCF Controls, now generally available (GA), are among the most eagerly awaited features for Power Platform developers, and for good reason.
As someone who values consistent user interfaces, one of the primary challenges I often encounter when implementing Web Resources and/or PCF controls is related to styling. It is no secret that the theme used by Model-Driven Apps differs from the one employed in Canvas Apps, and both, in turn, differ from the default Fluent UI theme.
In professional Power Apps development, this "inconsistency" often leaves clients with a subjective impression of poor quality. To mitigate this perception, developers frequently resort to manually adjusting CSS to create as much uniformity as possible across controls. However, this manual tweaking can be both time-consuming for developers who lack extensive frontend expertise and prone to requiring rework whenever Microsoft updates the design language of its applications.
One of the most exciting promises of Virtual PCFs directly addresses this pain point:
Wrapping Fluent UI v9 controls as a component is the easiest way to utilize modern theming because the modern theme is automatically applied to these controls.
Even if the Virtual PCFs are now GA, the page containing that statement has still the (preview) tag in it... π€
Does it truly deliver on this promise? Unfortunately, β the answer is no β.
Testing this is straightforward. Simply create a Virtual PCF after ensuring you have the latest version of the PAC CLI installed. In my case, I attempted to create a custom DateTime Picker that allows specifying seconds. It is a very simple control:
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react';
import { Input, makeStyles, tokens } from '@fluentui/react-components';
export interface IDateTimePickerControlProps {
theme?: any;
value?: Date;
isEnabled?: boolean;
onChange?: (value?: Date) => void;
}
const useStyles = makeStyles({
container: {
display: 'grid',
width: '100%',
gridTemplateColumns: '1fr 1fr',
'@media (max-width: 200px)': {
gridTemplateColumns: '1fr',
},
overflow: 'none'
}
});
const DateTimePickerControl: React.FC<IDateTimePickerControlProps> = ({ theme, value, isEnabled, onChange }) => {
const [dateValue, setDateValue] = React.useState(value?.toISOString().slice(0, 10) || '');
const [timeValue, setTimeValue] = React.useState(value?.toTimeString().slice(0, 8) || '');
const styles = useStyles();
const onDateChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const date = new Date(event.target.value);
const time = value || new Date();
date.setHours(time.getHours(), time.getMinutes(), time.getSeconds());
onChange?.(date);
setDateValue(date.toISOString().slice(0, 10));
};
const onTimeChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const date = value || new Date();
const [hours, minutes, seconds] = event.target.value.split(':').map(Number);
date.setHours(hours, minutes, seconds);
onChange?.(date);
setTimeValue(date.toTimeString().slice(0, 8));
};
return (
<div className={styles.container} style={{ gap: tokens.spacingHorizontalS, rowGap: tokens.spacingVerticalS, columnGap: tokens.spacingHorizontalS }}>
<Input
type="date"
value={dateValue}
onChange={onDateChange}
disabled={!isEnabled}
/>
<Input
type="time"
value={timeValue}
onChange={onTimeChange}
disabled={!isEnabled}
step={1}
/>
</div>
);
};
export default DateTimePickerControl;
I've then put that control in a Form and...
The field Start date is the one that uses my own control, while End date uses the standard one. As you can see even if I've not put any custom style in my control, the default style does not match the one shipped in the form π.
π Conclusions
Let me say, I've always been quite disappointed by this lack of consistency, since the beginning. One would expect that a huge company would have started with a framework and stay stick to it... but no, unfortunately we're still swimming in a sea of stratified libraries and versions.
For how long should we continue tweaking manually the UI to make it look professional?
FAQ
Why haven't you used the standard
DatePicker
control shipped by Fluent UI 9?
Simply because it's not part of the standard set of controls, but it's shipped via "@fluentui/react-datepicker-compat"
, that is not part of the default Virtual PCF framework.
Have you tryed the approach suggested by Diana's post, by wrapping the control in a
FluentProvider
?
Even if in the official documentation is stated that wrapping is only required when you want to apply a theme that is different from the one of the app, I tried and... Yes, the resulting effect is exactly the same π€.
Top comments (0)