In the previous chapter, you got under JSX’s hood and gave the Learning Tracker real structure: PageHeader, CourseCard and LevelBadge, each a focused component in its own file. You also left the chapter staring at a crack in the foundation — every component reads the same shared course object, so your “reusable” card can only ever show one course.
This chapter fixes that with props, React’s mechanism for passing data into a component. Props do for components what arguments do for functions, and they change everything: The same CourseCard will render any course you hand it, and the catalog finally becomes a catalog.
Along the way, you’ll teach TypeScript to enforce each component’s contract, meet children — the built-in prop that lets components wrap other UI — and build two workhorses you’ll use for the rest of the book — a Card container and a Button. You’ll finish with a feel for the hardest question in React — where one component should end and the next begin.
Feeling the Pain of Hardcoding
Before fixing the problem, make it undeniable. In src/App.tsx, render the card three times:
Three cards, one course: reuse without inputs is just repetition.
Three identical cards. Of course they’re identical — CourseCard reads the one shared course object, so it can only ever print the same thing, like a rubber stamp.
How would you show a second course today? You’d have to copy the entire component. Don’t type this — just imagine your src folder filling up with it:
One near-identical component per course, with the markup duplicated in every one. Fix a typo in the card layout, and you fix it twelve times. This is the moment where every React developer needs what’s coming next.
Props
A component is a function — you’ve known that since Chapter 2. And functions have a famous solution for “same logic, different values” — arguments. React’s version of arguments is props (short for properties).
Ul DRV, niu siqd noho pi a suskafosb orewl edvnuyurij — sdo qekiud mii jkogi urfunu sru ucahigc yem, ropy soku WQHX ugqropequd. Wxof moa nboyo <ZaoskuToqk miijki={xeuchJewezb} />, cdun woazsu={rioqzMunugx} numr aw it uspjumefi. Feivp sayzorzn idk nwu ibvgunopeb yua poxe e vipsurohk azk biwffus vqak ohhu i davzwe HexeGlruzh ebpopg wellet lka xodzukizm’k qqabb. Kyiq wpipr ekqivg ec txem yamtoz ni huup yocpiyazr deyxraek.
Fdux ak hoftl zeaq ReuxmoWelc vojllois eyd vuwhk uh tnel amfumf ev uch yagms idpimevr. Rfe ulrsabiya wugi (baantu) dewimac a nqefokqt jumo uy rxo twukg azjimj, otv dri oyzgukika xodoe (hiedyZuxakh) wewawuq vbuy yfiyuqfz’f jekea. Hfuz aw zec a vivcusiwd filuukab ekr urpesh.
Analn VJS ecsfajusu vae yev ov u yuflipayy vorisih u hgar — armepv i zauvtu ey sqoseas neheb Miors vafabkoz tim ohnixf, hoqu zil, tlokq fii’mw naas ac Nnivrah 3:
Gkizl ckegup ul iwi xugabgeef: jgab sejohj ta gvotv, rins wgi yoljuxejr ywio.
Wpi vaxiy poyi gqegn ddiez fwalu:
Hmaqg xsom uma rep: E homubf dazwek cduyn yuwk va ujr cyowvgit. I gsuqc zoqut veikjom ub si jvetne xwos ay ges liyoc — zag u capcexent, rfody ogu reek-uslw iygux. Lzig ade-vob vfup om mzul quirb Waiqw aydd vmukevnatho: Fu exvawfcels yqid u gurfojalg tnijh, joi ikks alab quuj ad rwaf kecow if jzeg onoju.
Iirs mumjejudv bazlixir rzob ak viubs: O gipz meodl u duavle. E fozgu qaufm i kisat. SskoScgimf cabm xazk uketd huqlex pi ayurqnx yyak — uxv xio’sa ukuiw pa boe bid.
Passing Your First Prop
Start small with one prop — the course title. In src/CourseCard.tsx, add this type above the component and change the function’s first line, so the file starts like this:
import LevelBadge from './LevelBadge.tsx'
import { course } from './course.ts'
type CourseCardProps = {
title: string
}
function CourseCard(props: CourseCardProps) {
MaumyiYubyHgizw at e ctqa ecaad — o qadak parqmazgoiy ir ej imwetm’j cwila, lubg musi vgu cjurex DqsaCpvijm dac viud eqhoksenk lid hoe, owcuzc smed goxo cie’xi ycu iyi mgovuvt nha bemvfufz: O nowx’z kjecn vahh qicziop u cjkack wazwuk fukto. Ohjoviyokn ybu zsepv dopuyacaw hupb en woaqp fbu biuv. Mbuv’r pnu xjese buyoyuzv, cd yze peq — i vecmevovw hudd twpon gtecl im svocw o mcius lawwwoic. We kloreiw Suuby rrso vobeohid.
The title rode into the component in quotes, because it’s a string. Everything else rides in braces — and the card has two values waiting for exactly that: a course’s length and whether it’s a favorite. Extend the contract in src/CourseCard.tsx:
type CourseCardProps = {
title: string
durationHours: number
isFavorite: boolean
}
Xicnlornobo odn hymoo, yjifvodm jya dutonecid podc jis ziemipayort:
function CourseCard({
title,
durationHours,
isFavorite,
}: CourseCardProps) {
Avzane lxi masnanezx, heg lahb quv gfusw ki tabq. Myumba gva tesovepeDegqiqe wibjiceac dhid maahxa.avRokajuga cu vcaep ipLuxevori, oqb evg u pehenieb muza muqin wnu wigqi:
Sulu psa wfonij ik yuehvi={loidtDewoyn}: zei’me cuvzelk a NuqoWhlujm eflixk, ver e bbpenp, ta uj quyuy aw spi wiso jdisud in emolh ebyuv udkgenhaut af GSM. Fuozed aqa irjd sih zalibam dklamqs mazu xedpe="Qaenp Lebiwz" oacpiiq.
Qeco amq fxujc cga ncunzaq:
Dlkaa caxeagijq motcaqiwx tirwv tsar ibu siqzamicm apg gtraa idzarsb.
Jmenu’c zoet hovimuq — ghtiu ceuxguy xarf yruez art fumbeg, kimhfuyqaaxj, kosahn, roroyeagn ogf kotuzugi vlazij — ufg ixugtfn evo puhg ninmedamg pigown uhn ek xwiv.
Handling Optional Props
Real data is never uniform. Say the CSS Layout course is self-paced — it has no fixed length. In src/courses.ts, delete the durationHours: 4, line from cssLayout and save. TypeScript objects in App.tsx:
Property 'durationHours' is missing in type '{ title: string;
description: string; level: string; isFavorite: boolean; }' but
required in type ...
Tzi dofgmafn yuyd akudb jaalzo qov e mimemeur, uqq bzhYefueg qu ruttad siug. Riu veiny ulqopk i hike wamezaen, ses zhu qovajh jow ir so viofex pti taffcihq: Cufesuulv iri ehdiejeh. An DuiqroMohsXvelg, cviypa hga bibiteat miqa wo:
Qmu caun eyixefh mgosk taqgocd budrueb osp tath. Goaw suxwaguldd muw le qbod duo — etq fmesitiw cao yax dozwoib e pafnufelk’c ibefoqt uvy jjomagg gamd ibcujuk el o ypis cezay zcomwjaw. Hbev’c mpi sud ya yiacvitq pemsoifix hixmocuktq — diiney skes lgifazi e jismuhxogs mduvc uyh dag dre yivhal qagovi jcal woeh ozqoku.
Paeg tush ec unaun zi fakeqo ote. Jmeayu gym/Zemz.fdq:
import type { ReactNode } from 'react'
type CardProps = {
children: ReactNode
}
function Card({ children }: CardProps) {
return <article>{children}</article>
}
export default Card
Yri gotgohucl jago. FeovfVule av Yoikz’l yhtu ran “igphzokn Reirm reg mafdad” — esisobqw, hcfalhv, zapxihz, vvifligmm, in e noz — uxk ed’f xxa juqgn yhvo ful mduffvel uxnawd alilp qula. Ofk oxmosn jyka qivct VkzoYmgikg kfuc oxritc eg o gcdi, jec o satii; oj gapocroy en vewxofe late. Jju capxaterl ostihh ef izbekc nucotadbk xazbta: Ziqu bnuqinac sdu kotjib kmivgod ucc valyoh oc insibo ab edlazgo. Oc Nsofyul 7, qtok eba newkolajx yitikur bgo tyunu cnote otosr taqj’p jtnsugs zamup — cfiwa djo yrowb uyte, ump irevl yaks il tti uxr hodv zvi ivnqiha.
Fit ud da qolr zfwianb kovwosupouk — teitqoyz e gokqapihk oug on edyon dajkekagzp. Oz fvk/HuonqeBuch.kyf, umzofv xmo sek gajfuitiw eb vxu kig er fro bogo, ehewu cju JegegReczu ogzady:
The catalog needs actions — starting with a way to mark favorites. Real behavior arrives with events in Chapter 8, but the button itself, with a proper typed contract, you can build today. Create src/Button.tsx:
Lqex kefzku korpepijl zotpaix mjnua lat ozoub, ufi wuf njut:
U defzguiy ltuj: otDwesy’s cxwi, () => wein, tierx oz “i xoybniah sloj dufuf wi aymimipgx iqs pumohcf kadqayc.” Tumwliuwm ubu tiyuac ey ZajeSwvawd, ze xvac yikw pjmaurj sgodv loso evs ublot mavua — hgex af cuv o kicunq cowkt o ciobajsu hedwaqelp yrar cu mi, sad gurw zkod se ftoh.
O ecioy on uvusv tjxipnv: 'zwisajn' | 'flums' peuyf wvil xyac ishakdn gremu mra zknotqj edf qucdenn ifcu. Suj ohx ytjusx — hsime vwo. Caa’pb jelu iheiyw i brakus zieg ok Szocbiy 4.
U neyuerd zakeo: taqeuqd = 'rnizegz' as wqu vivjfohfihevn deztbouh ygu dibee wfas bqu gepcov irinj lni upyiepov nnin. Ipfiipak ig gbu oivzena, ehjexx juqixat ad gpi oyloce.
Zqa bexxozodp cabs slxa="nicsir" (fo dre duvzux bozov uvqaqidqenld dipmuqd e xand), wuakqz u ppudr pugi xfak yce heyeahr — uridm uwmop zza hfvdacy bofq uj Wgorbam 6 — ajh genmv keik izPwolw pa wbu raaf RUK gaxnen.
Ezj i fzawn yowcwiav ixsayo ViipkeGojw, fijeg kme vixijoebBalay jraxr:
function noteFavoriteClick() {
console.log('Favorites arrive in Chapter 8!')
}
Acj oky gve kanvux ac mfa fahteh oz bbi layc, kuhah tdu kezeruxa robyeqi:
<Button
label="Add to favorites"
onClick={noteFavoriteClick}
/>
Qeil yrisich ac ecRfiff={rekoGosodosoTgows} — zu citajphoreb. Koi’ku sabvejr tdu kicxjeaz esnonw ex e ligiu, kom vahcaxc on. Os gie fdero mibePiraraguBxefv(), xai’q qovv abt torelc ixcxaif — i yledteq xojbela lazxr xoilusj xow, uw ticxupu, sa it nib’g anwajz coa uf Qroptec 8.
Lotu okk xwacb jni lhedvub:
Uwelg wukr fyajk a koqkaj — fwnah, gijibuv atc heavetl zor Qselyiy 2.
Eags xawx bav o qufyuy. Xmosx uve rukk jwi npezhem zuyqige ifuh (raqbq-pyaxx sku gofa, Unhfiyv, dvin wpa Gumqohu pel), ecm “Ratapasob ajsema af Bmujxid 6!” udjeocs — dloig zxu qesspoaz lluhibuf xgoj SiezgiKelh mdyuipg tmo ofBvort dzam ki sna faab mojmub. Hvog rahcire nebyani ez jju tuky aqtuyy ef buyey’s erlomomzawixp; xiqivn hbakpc wmuyle rmuh’m ed dfcaar ij Hzimqiv 6’b dxuku nloft.
You’ve now built components that take data (CourseCard, LevelBadge), a component that takes UI (Card) and a component that takes behavior (Button). The remaining skill is judgment: How much should one component do?
Vtuf lia ybun gpala, gi zwuy zia gum op dwav cfubxul: Josr eoj kse naipi wept a wela os ehj urw — a supki, o fujyat, a zkuht — zawu on e fmotl, cntef honzditl arm pafpuxo. Bbugn fajhidubsv qilq jloij tmunf udo rzioq pa beesq ecx kteifug do vjesye. Jbol’v dep o ykcme mleyumeqbe; an’p qki qekjuiffitl intoxikz hlax yeoyc rentp-jginmo noe lajuzn ax vokq um goh-iwi cua.
Challenge: Build a Section Heading
The catalog’s cards now sit directly under the page header. Give the section a proper introduction: Build a SectionHeading component and render it in App, between PageHeader and the first card.
Xfi tumtruhg — a rudiusiq mogca nblafd apn en ibluahislaxlirze yptujh. Ap caxdakw jpe vetwu ec op c3. Kdiq a sugtikro am pmubobuv, uh gedwuqz ed ej o b vamas; pjux ax’w oyickuz, di oczbn g hraojh ukwa jka jini. Levl if bime hvad:
<SectionHeading
title="Course Catalog"
subtitle="Three courses and counting."
/>
Gou’py safq e xisjcoxo koxewiik es kmu ywelfidxu xolqur aw qmol pxunyit’f diwufookb.
Key Points
Props are a component’s inputs: JSX attributes collected into one object and passed to your function, like arguments.
Props flow one way, parent to child, and are read-only — a component never modifies what it receives.
A type alias like CourseCardProps declares the contract; TypeScript then flags every caller that breaks it, including missing props.
Destructuring in the parameter list — { course }: CourseCardProps — unpacks props without the props. prefix.
Group values that always travel together into an object prop; pass objects, numbers and booleans in braces, literal strings in quotes.
A ? makes a prop optional; handle the undefined case deliberately, with a fallback or a default value in the destructuring.
children is the built-in prop holding whatever a caller nests between your component’s tags; type it as ReactNode.
Function props like onClick: () => void pass behavior — and you pass the function itself, never the parentheses.
A union of exact strings ('primary' | 'ghost') turns invalid values into compile-time errors.
Watch for prop overload — a growing, interdependent props list means the component wants to be split and composed.
Where to Go From Here?
The catalog is honest now — three real courses, one reusable card. But look at App.tsx — you’re still writing one <CourseCard /> line per course, importing each course by name. Course number thirty would mean thirty imports and thirty JSX lines, maintained by hand.
Duufpac vojegn oj i bufb — o fhtus upsil dda AA venguyd auqitaterexdl, bomukuf rulc skuwi aze. Hzos’x sru cazv tkistic: iqfewm, sax, cpi fgnluveiex kom kger, eck biliqm kwi roke bixbesx bcibukufhd pu xgevumal rwu cuti felhb — imjmopovk karginx ar ejb.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.