Create custom field

default discord avatar
<Clement/>
3 months ago
67

I try to create my first custom field.



The doc example



How to import React.FC if React deps are not installed

  • default discord avatar
    paulpopus
    3 months ago

    You should be able to add react at the top


    import React from 'react'


    Is that not the case?

  • default discord avatar
    <Clement/>
    3 months ago


    im using pnpm

    image.png
  • default discord avatar
    paulpopus
    3 months ago

    Ahhh, then you may need to install React yourself



    pnpm works a bit differently out of the box compared to yarn

  • default discord avatar
    <Clement/>
    3 months ago

    ok then the same version: ^18.2.0 I see



    There is no UI Kit right? or there is maybe a way to get the same css?

  • default discord avatar
    paulpopus
    3 months ago

    Here's some links:


    https://payloadcms.com/docs/admin/customizing-css
    https://payloadcms.com/docs/admin/components#styling-custom-components


    There's no UI kit in the sense that you can see what components are available to you easily,

    yet


    A storybook implementation is in the works that would let you see what you have available, however you

    can

    reuse components



    but you need to check out existing code from core and plugins to figure out their paths and what's available 😬

  • default discord avatar
    <Clement/>
    3 months ago

    ok ok

  • default discord avatar
    paulpopus
    3 months ago

    If you want a simple component styling, the easiest way is to look into the css variables globally available

  • default discord avatar
    <Clement/>
    3 months ago

    last question, the example code has a problem no?

    image.png
  • default discord avatar
    paulpopus
    3 months ago

    So you can at least write your own css using the variables thats gonna make it compatible with dark/light mode and re-use similar colours and vars

  • default discord avatar
    <Clement/>
    3 months ago

    my screen stay blank , but no error in console

  • default discord avatar
    paulpopus
    3 months ago

    Yes...The code itself I think is correct but the types are wrong



    Here's an example component of mine building a number field with the react module



    import React from 'react'
    import { useField } from 'payload/components/forms'
    import { NumericFormat } from 'react-number-format'
    import { TextInput } from 'payload/components/forms'
    import { Label } from 'payload/components/forms'
    import { RowAdmin } from 'payload/dist/fields/config/types'
    import { transformPriceString, reversePriceToString } from '../utilities/transformPriceString'
    
    type Props = {
      path: string
      showError?: boolean
      readOnly?: boolean
      className?: string
      required?: boolean
      placeholder?: Record<string, string> | string
      style?: React.CSSProperties
      width?: string
      label?: string
      admin: RowAdmin
    }
    
    const PriceInput: React.FC<Props> = ({ showError, readOnly, className, required, path, placeholder, label, admin, ...others }) => {
      const { value, setValue } = useField<number>({ path })
      const [visualValue, setVisualValue] = React.useState<number | string>(reversePriceToString(value))
      const { style, width } = admin
      const classes = ['field-type', 'text', className, showError && 'error', readOnly && 'read-only'].filter(Boolean).join(' ')
    
    
      return (
        <div
          className={classes}
          style={{
            ...style,
            width,
          }}>
          <Label htmlFor={`field-${path.replace(/\./gi, '__')}`} label={label} required={required} />
          <NumericFormat
            onChange={(e) => {
              const transfomedPrice = transformPriceString(e.target.value)
    
              setVisualValue(e.target.value)
              setValue(transfomedPrice)
            }}
            value={visualValue}
            id={`field-${path.replace(/\./gi, '__')}`}
            name={path}
            fixedDecimalScale
            required={required}
            thousandSeparator=','
            placeholder={typeof placeholder === 'string' ? placeholder : '$24,000.00'}
            prefix='$'
            decimalScale={2}
          />
        </div>
      )
    }
    
    export default PriceInput
  • default discord avatar
    <Clement/>
    3 months ago

    Ok thx, I will try with your example 👍

  • default discord avatar
    paulpopus
    3 months ago

    The TextInput from there is actually unused, I think I had an issue with props or ref forwarding

  • default discord avatar
    <Clement/>
    3 months ago

    ok ok, anyway I will start with a simple field



    I don't understand, what should I set in 'path', it's the component name?

  • default discord avatar
    jarrod69420
    3 months ago

    custom components are passed down a "path" property, it is used as a key to store the value in form state. TLDR; it is provided for you.

  • default discord avatar
    paulpopus
    3 months ago

    Everything in the props above there is passed down into your component, some of them are things from the field configuration

  • default discord avatar
    <Clement/>
    3 months ago

    oh ok I see 🙂



    Am I doing something wrong? Path seems to be undefined





    My component



    The way I call it :



    then the value is never saved in DB

    image.png
    image.png
  • default discord avatar
    paulpopus
    3 months ago

    I think it's cause you're using the

    ui

    field



    It's more of a "insert your react components here" field than a data field to my knowledge



    So use a

    text

    or a

    number

    field for example if you wanna store a particular type of data but override the frontend component of how it looks or functions



    I use the UI field for buttons that trigger other behaviours for example, or for pulling in visual information. ^ my example I posted above is attached to a number field



    I haven't tried the

    ui

    field for data at all tbh 🤔

  • default discord avatar
    <Clement/>
    3 months ago

    ohh ok, I thought "ui" was the only field that could receive admin > components > Field



    better, but nothing happens when I save it 😬



    it's ok, I just add the label, and the input type 🤷‍♂️

  • default discord avatar
    jarrod69420
    3 months ago

    nope, any field can use custom components 🙂



    You are likely looking to use a

    text

    field with a custom component, so you can save the data from your custom component?

  • default discord avatar
    <Clement/>
    3 months ago

    Yep, its working finally 😁


    I just copy the same structure than the others inputs (name, htmlFor, classname ...), and now looks like a official one :

  • default discord avatar
    paulpopus
    3 months ago

    When in doubt you can just go into the core code of payload and see how all the different types of fields are constructed



    Ill send some links a bit later when im at my laptop

  • default discord avatar
    <Clement/>
    3 months ago

    Yep, I think there is an util function to transform the input name to get the Title (with word spacing and uppercase)

  • default discord avatar
    paulpopus
    3 months ago

    Most stuff from core can be imported even if your ide doesnt autosuggest



    Just use the more absolute path

  • default discord avatar
    <Clement/>
    3 months ago

    I did not see a way to add custom behavior to "readOnly". I can only set a boolean, we don't have access to data?



    pretty nice

  • default discord avatar
    paulpopus
    3 months ago

    What do you mean?



    Youre getting a boolean readOnly...you can choose what you actually do with it

  • default discord avatar
    <Clement/>
    3 months ago
    image.png
  • default discord avatar
    paulpopus
    3 months ago

    On fields you can also use custom for anything unique to your fields config

  • default discord avatar
    jarrod69420
    3 months ago

    you will need to import and use some of our exposed hooks:

    https://payloadcms.com/docs/admin/hooks
  • default discord avatar
    paulpopus
    3 months ago
    custom

    on the field configuration

  • default discord avatar
    <Clement/>
    3 months ago

    I try to reproduce my Sanity template, I lastely I was able to set readonly, depending of other fields

  • default discord avatar
    paulpopus
    3 months ago

    📵



    ill check back in here in a couple of hours

  • default discord avatar
    <Clement/>
    3 months ago

    that's really nice, thank you 🙏

  • default discord avatar
    jarrod69420
    3 months ago

    in a custom component, you will need to access the form data with the hooks I linked above

  • default discord avatar
    <Clement/>
    3 months ago

    yep, but in a current payload field, is there a way? In my Sanity template, I created a "link" field.


    readOnly: is set to true if the "Page" field is already set.

    image.png
  • default discord avatar
    jarrod69420
    3 months ago

    No, it is currently just a boolean. But it would be pretty simple to create a custom component like so:



    import React from 'react'
    import { Text, useField } from 'payload/components/forms'
    import { Props } from 'payload/dist/admin/components/forms/field-types/Text/types'
    
    export const ConditionalField: React.FC<Props> = incomingProps => {
      const { value: watchValue } = useField({
        path: 'field-to-watch',
      })
    
      const readOnly = !watchValue ? false : true
    
      const props: Props = {
        ...incomingProps,
        admin: {
          ...incomingProps.admin,
          readOnly,
        },
      }
    
      return <Text {...props} />
    }


    or if you don't want to create a new object, you could mutate the incomingProps with

    incomingProps.admin.readOnly = !watchValue ? false : true

    and spread that into your <Text {...incomingProps /> component

  • default discord avatar
    <Clement/>
    3 months ago

    Thx so much 🙏

  • default discord avatar
    paulpopus
    3 months ago

    Nice, you got it handled!

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.