Hey folks!
I am trying to build a custom icon selector component:
'use client';
import type { TextFieldClientComponent } from 'payload';
import { FieldLabel, useConfig, useField } from '@payloadcms/ui';
export const IconFieldComponent: TextFieldClientComponent = ({ path, field }) => {
const { config } = useConfig();
console.log('config', config);
const { setValue, value } = useField({ path });
console.log('path, value', path, value);
return (
<div>
<FieldLabel htmlFor={path} label={field.label} required={field.required} />
{/* To be continued ... */}
</div>
);
};
export default IconFieldComponent;And I am trying to use it in the field like this:
export const iconField: Field = {
name: 'icon',
type: 'text',
label: 'Icon',
required: true,
admin: {
components: {
Field: '@/fields/Icon/IconFieldComponent.tsx',
},
},
};If I remove the
useFieldand
useConfighook, the field gets rendered and I can see my label. But with the hooks (
useConfigis the culprit), I get the following error message:
TypeError: Cannot destructure property 'config' of [...] as it is undefined.Does somebody know what could be wrong here?
In 99% of cases, this happens if you have a different version of
@payloadcms/uior react installed than what the Payload Admin Panel is using
If would verify you only have one version installed, e.g. by running
pnpm why @payloadcms/uiTrying different package managers may also help
Thanks
@360823574644129795! I created a brand new payload app and copied the dependencies from there.
Hej
@295279398930743307- did you manage to implement it? I am having a real hard time and the Docs do not help unfortunately.
The icon selector?
Yes.
Sure! So this is my field definition:
import { Field } from 'payload';
export const iconField: Field = {
name: 'icon',
type: 'text',
label: 'Icon',
required: true,
admin: {
components: {
Field: '@/fields/icon/IconFieldComponent.tsx',
},
},
};And this is my custom component whch then renders the selector.
'use client';
import type { TextFieldClientComponent } from 'payload';
import { ICONS } from '@/components/Icons/constants';
import { FieldDescription, FieldLabel, useField } from '@payloadcms/ui';
import './IconFieldComponent.scss';
import { cn } from '@/utilities/cn';
export const IconFieldComponent: TextFieldClientComponent = ({ path, field }) => {
const { setValue, value } = useField({ path });
const appearancePath = [...path.split('.').slice(0, -1), 'appearance'].join('.');
const { value: appearance } = useField({ path: appearancePath });
return (
<div className="useTw">
<FieldLabel htmlFor={path} label={field.label} required={field.required} />
<div className="flex gap-4">
// I have all of my icons mapped to their names, so I iterate over the names and get the corresponding component and render it
{Object.entries(ICONS).map(([iconName, IconComponent]) => (
<div
className={cn({
'icon-selector': true,
'icon-selector--primary': appearance === 'primary',
'icon-selector--secondary': appearance === 'secondary',
})}
key={`${path}-${iconName}`}
>
<input
type="radio"
id={`${path}-${iconName}`}
name={path}
checked={value === iconName}
onChange={() => setValue(iconName)}
style={{
appearance: 'none',
display: 'none',
}}
/>
<label htmlFor={`${path}-${iconName}`}>
<IconComponent />
</label>
</div>
))}
</div>
{field.admin?.description && <FieldDescription path={path} description={field.admin.description} />}
</div>
);
};
export default IconFieldComponent;And for the sake of completness, also so styling (not my best work and using tailwind):
.icon-selector {
@apply flex h-16 w-16 items-stretch justify-center rounded text-white;
outline-offset: 2px;
outline-width: 2px;
outline-style: solid;
&--primary {
border-color: var(--color-primary);
background-color: var(--color-primary);
&:has(input:checked) {
outline-color: var(--color-secondary);
}
}
&--secondary {
border-color: var(--color-secondary);
background-color: var(--color-secondary);
&:has(input:checked) {
outline-color: var(--color-primary);
}
}
label {
@apply flex flex-grow cursor-pointer items-center justify-center p-1;
}
}Awesome, thanks!
Thank you so much for helping me out with this one. I spent way too many hours with setting this up. The docs are kind of lacking right now and this really helped me. Again, thank you so much!
Star
Discord
online
Get dedicated engineering support directly from the Payload team.