Discussion about using card parameters and custom block types in a React component.

61 replies
Last updated: May 29, 2022
hi, i dont understand why i cant use my card parameter in my react component
{cards.map((card, index) => {
        return <Card position={{ top: "top-[200px]", left: "left-0" }}>
          <PortableText
            value={data[0].card}
            components={portraitPortableTextComponents}
          />
        </Card>
      })}
AI Update

The issue is that you're not using the card parameter from your .map() function - you're referencing data[0].card instead, which means you're always rendering the same card content for every item in your array.

Here's the fix:

{cards.map((card, index) => {
  return (
    <Card position={{ top: "top-[200px]", left: "left-0" }}>
      <PortableText
        value={card}  // Use the 'card' from map, not data[0].card
        components={portraitPortableTextComponents}
      />
    </Card>
  )
})}

What was wrong:

  • cards.map((card, index) => {...}) gives you each individual card item as you iterate
  • But inside, you were using data[0].card, which always points to the same card in your data array
  • This means every iteration rendered the same content

Additional tips:

  1. Add a key prop - React needs this for list rendering:

    <Card key={index} position={{ top: "top-[200px]", left: "left-0" }}>

    Or better yet, if your cards have unique IDs: key={card._id}

  2. Check your data structure - Make sure cards actually contains the portable text content you expect. If cards is an array of objects and the portable text is nested (like card.content), you'd use:

    value={card.content}
  3. Verify portable text format - Ensure each card contains properly formatted Portable Text (an array of blocks), not just a string.

If you're still having issues, check the console for any errors and verify what cards actually contains by logging it: console.log(cards).

Without sharing an error, an issue, your schema, more code or some additional information, there is not much we can help with… 🙂
i have no error my ide simply doesnt let me use the card argument in my function
What do you mean “doesn’t let you use”? Your IDE is not your boss, you write the code. 😹
well he kinds of know better than me what i can or cannot di
{cards.map((card, index) => {
        return <Card position={{ top: card, left: "left-0" }}>
          <PortableText
            value={data[0].card}
            components={portraitPortableTextComponents}
          />
        </Card>
      })}
Can you share a screenshot?
for the first card parameter in the CArd component i cant use my card parameter
I mean, there is nothing from what I can see that “doesn‘t let you use” that variable?
I still don’t understand what you mean with “can’t use.” It’s undefined or empty? Is it what you mean?
but not inside my portabletext
my ide doesnt show it as a parameter
Sorry?
I’m sorry, I genuinely do not understand what you mean, and the screenshot you shared doesn’t illustrate what problem you are facing with your IDE. 😞
alright
Looking at that screenshot, the
card
and
index
arguments are dimmed because they are not used within that closure.
i used card in the portable text
Not that I can see, no. You use a different variable:
data[0].card
. That might not be the same as the
card
argument.
alright i see
Right now, your code shows that:• You iterate over a
cards
variable, which is therefore an array.• For each item in the
cards
array, you render the exact same JSX chunk, since you use neither the
card
argument nor the
index
argument.• Your portable text will always be rendered with the same thing right now.
i was hoping to get a different value from the different cards i have$
I can’t really help without knowing more about your schema. What is
cards
? What is
data
?
i solved my problem i was going on a dead end
i opted for this
<Card _position_={{ top: "top-[350px]", left: "left-0" }}>

<PortableText

_value_={data[0].card1}

_components_={portraitPortableTextComponents}

/>

</Card>

<Card _position_={{ top: "top-[200px]", right: "-right-0" }}>

<PortableText

_value_={data[0].card2}

_components_={portraitPortableTextComponents}

/>

</Card>

<Card _position_={{ top: "top-[440px]", right: "-right-[0px]" }}>

<PortableText

_value_={data[0].card3}

_components_={portraitPortableTextComponents}

/>

</Card>
if i want to add a card ill just have to uopdate the value of the portable text
and update my schema
schema :
{

name: "card1",

title: "Texte personnalisé",

type: "array",

of: [

{

type: "block",

// Only allow these block styles

styles: [

{ title: "h1", value: "h1" },

{ title: "h2", value: "h2" },

{ title: "h3", value: "h3" },

{ title: "h4", value: "h4" },

{ title: "h5", value: "h5" },

{ title: "h6", value: "h6" },

],

marks: {

decorators: [

{ title: "strong", value: "strong" },

{ title: "em", value: "em" },

{ title: "strike", value: "strike" },

{ title: "underline", value: "underline" },

{ title: "blue", value: "blue" },

{ title: "green", value: "green" },

{ title: "animation", value: "animation" },

{ title: "muted", value: "muted" },

],

},

// Only allow numbered lists

},

],

},

{

name: "card2",

title: "Texte personnalisé",

type: "array",

of: [

{

type: "block",

// Only allow these block styles

styles: [

{ title: "h1", value: "h1" },

{ title: "h2", value: "h2" },

{ title: "h3", value: "h3" },

{ title: "h4", value: "h4" },

{ title: "h5", value: "h5" },

{ title: "h6", value: "h6" },

],

marks: {

decorators: [

{ title: "strong", value: "strong" },

{ title: "em", value: "em" },

{ title: "strike", value: "strike" },

{ title: "underline", value: "underline" },

{ title: "blue", value: "blue" },

{ title: "green", value: "green" },

{ title: "animation", value: "animation" },

{ title: "muted", value: "muted" },

],

},

// Only allow numbered lists

},

],

},

{

name: "card3",

title: "Texte personnalisé",

type: "array",

of: [

{

type: "block",

// Only allow these block styles

styles: [

{ title: "h1", value: "h1" },

{ title: "h2", value: "h2" },

{ title: "h3", value: "h3" },

{ title: "h4", value: "h4" },

{ title: "h5", value: "h5" },

{ title: "h6", value: "h6" },

],

marks: {

decorators: [

{ title: "strong", value: "strong" },

{ title: "em", value: "em" },

{ title: "strike", value: "strike" },

{ title: "underline", value: "underline" },

{ title: "blue", value: "blue" },

{ title: "green", value: "green" },

{ title: "animation", value: "animation" },

{ title: "muted", value: "muted" },

],

},

// Only allow numbered lists

},

],

},
let me know if i can make it better but im quite satisfied with it
If
card1
,
card2
and,
card3
have the same block type, I don’t see why you need to duplicate them 🤔.
You can create an array of cards instead, and get the data with
cards[index]

[EDIT] if you want to limit the number of items in your array, you can add validation rules.

  {
    title: 'Cards',
    name: 'cards',
    type: 'array',
    of: [{ type: 'block' }],
    validation: Rule => Rule.max(3) // 3 items max.
  }
if your cards need to contain more information, you can create a card object (singular) and do:
 {
    title: 'Cards',
    name: 'cards',
    type: 'array',
    of: [{ type: 'card' }]
  }

export default {
  title: 'Card',
  name: 'card',
  type: 'object',
  fields: [
    {
      title: 'Title',
      name: 'title',
      type: 'string',
    },
    {
      title: 'Content',
      name: 'content',
      type: 'cardBlock', // custom portableText
    },
    {
      // more fields...
    }
  ]
}
excuse me but i don't see the point about this line of code
{
    title: 'Cards',
    name: 'cards',
    type: 'array',
    of: [{ type: 'block' }],
    validation: Rule => Rule.max(3) // 3 items max.
  }
since in my editor i only have one rich text field
i'd like to have 3
or more
when i see
type: 'cardBlock'
I don't understand either since i thought you could only set it to block
u mean i should replace all my cards1 cards2 cards3 with
{
    title: 'Cards',
    name: 'cards',
    type: 'array',
    of: [{ type: 'card' }]
  }

what will differentiate card 1 from card 2 from card 3 if i only have one rich text ? and get the correct index ?
An array let you create any number of
card
you want, making it more reusable, rather than hardcoding 3 cards.
cardBlock
was an example, but if you want to reuse your
block
, I’d suggest to create a custom block type:
export default {
  title: 'Custom PortableText Block',
  name: 'customPortableTextBlock',
  type: 'array',
  of: [
    {
      // add your configuration here
      type: 'block',
      styles: [],
      lists: [],
      marks: {
        decorators: [],
        annotations: [],
      },
    },
  ],
}
then you can reuse it elsewhere:

{
  title: 'Main Description',
  name: 'mainDescription',
  type: 'customPortableTextBlock'
},
{
  title: 'Author Description',
  name:  'authorDescription',
  type: 'customPortableTextBlock'
}

when you say i can use it elsewhere where in which document do you make reference ?
in another schema ?
alright i understood
i have one last question
is it possible to have richtext inputs only on certain documents ?
or schemas are always the same for all the documents of a certain types
anyway thank you all very much for your help im grateful
If you make your field not required, then it can be filled on some document and not on others.
good to know. But for the moment i will make a schema for each section so each field will be required
thanks for the info
I have an error when i try to add multple cards
when i click on te block component i get an error
same error when i press the add item button
_export_ default {

title: "Card",

name: "card",

type: "object",

fields: [

{

title: "Title",

name: "title",

type: "string",

},

{

title: "Content",

name: "content",

type: "block", _// custom portableText_

},

],

}
{

title: "Cards",

name: "cards",

type: "array",

of: [{ type: "card" }],

},
i(m suspicioous about this line
type: "block", _// custom portableText_
i know how to use portabletext on the frontend but have no clue on the sanity side
You need a custom block type here. You can refer to my previous example with the customPortableTextBlock. And of course this can be named whatever you want.
man you helped me so much
sanity is way more clear for me
i'm having a blast devlopping with it
learning nextjs along with it so much to digest
😀
Glad it helped 👍

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?