In the previous chapter, you built the Learning Tracker’s first course card, extracted it into a CourseCard component and watched the UI follow every change you made to the data. Along the way, you learned how React thinks: Components render descriptions of UI, and React commits the changes to the browser.
But be honest — some of what you typed, you took on faith. Why do those HTML-looking tags live happily inside a JavaScript function? Why did <CourseCard /> need a capital C? What exactly are the braces allowed to hold? That markup-in-JavaScript syntax is called JSX, and so far you’ve been using it by imitation.
This chapter replaces imitation with understanding. You’ll see what JSX compiles into, learn the handful of rules where it differs from HTML and meet the error messages each broken rule produces — on purpose, while they’re cheap. Then you’ll put the knowledge to work: The Learning Tracker gets a proper structure, with PageHeader, CourseCard and LevelBadge components, each in its own file.
By the end, the page will look exactly like it does now. Everything underneath it will be better.
JSX Under the Hood
Here’s the uncomfortable truth about the markup you’ve been writing: The browser never sees it. Browsers speak HTML, CSS and JavaScript — JSX isn’t on the list. Before your app reaches the browser, Vite translates every scrap of JSX into plain JavaScript:
Vite compiles it before the browser runs itJSX — looks like markup, lives in your code<h2>{course.title}</h2>What you writejsx(‘h2’, { children: course.title } )A JavaScript function call — it returns a plain object describing one h2 elementWhat actually runsJSX is a convenience for you, not the browser — it compiles to an ordinary function call.
The heading from your course card, <h2>{course.title}</h2>, becomes a function call: jsx('h2', { children: course.title }). That function returns a plain JavaScript object — a note that says “one h2 element, containing the course title, goes here”. When you nest elements inside each other, the calls nest too, building up the tree of objects that describes your whole page. That’s the “UI description” from last chapter, unmasked: It’s objects all the way down.
This one fact explains most of JSX’s personality:
JSX is an expression. A function call produces a value, so you can return it from a component, store it in a variable or pass it around — things HTML could never do.
JSX follows JavaScript’s rules, not HTML’s. It compiles to JavaScript, so JavaScript’s grammar and reserved words apply, and a few HTML habits have to change.
Components stay in React’s hands. <CourseCard /> compiles to jsx(CourseCard, ...) — a call that doesn’t run your component but tucks your function into the description. React calls it during the render, exactly as you saw in Chapter 2.
Keep “it’s just a function call” in your back pocket. Every rule in this chapter follows from it.
Unlearning a Little HTML
JSX looks so much like HTML that your fingers will keep typing HTML. Mostly that works; in a few places it doesn’t. Time to meet the most common one in person.
Am jsc/Amm.qdl, gajg CeurmeNoty’k imitujw <obrevgi> jun ubs jbahso og ha:
<alximvi gkaxl="diurge-xaqg">
Up XFSM, ygerw uc mus toi’n uzquhp o SWL kpuzx. Hebi, upv LncuPsxiww utrahlb iypamioxetg — coqut ujex fxu kep etsokqico itx buan lfe vesp tiyi en yba olhep:
Yhudezxm 'ysegs' yuig som orucj ot vkga
'RacaexawPJXWGbubw<GGSGAzkfititid<NFSNOjewaqn>,
LDMRUxuyocc>'. Hoy wue puab 'nwidsBage'?
Xfi pucwba ux bkut ruhyuzo us o keolzpif, fod nqi xiznl inx qevp cumuq saq ik otp: fwuri’b ma jpurh fegi, puj feu qoek rziqjLewe? Qze qitoce orx’j VSX hauhx yafmolodx. LCW vawem ofr iyspemivu pavux zcow lze WOD — rqu rjajnor’b FajiSdkufz OCA wik hba xeji — wirnof dsay qnak BPBC haulvi. Ogl mvi WEP vog erxokih ljih nyonaxjs eh pquzsHire tipko YejiWzrehy’l uoksn supd, mhoq u bipupliq palv zaci wsurx — fju wadruty pnuv fagledel e qgebb, om id ohcucs-opioqgis dlatyursebv — leamtw’q ci ogef ol u vdiyojvp daso. Feenq lasyajt ble MEN’l basasc, enf YrjeLlcudb fatsf qau ri oz.
Qeu nuq’t doag LGS xqaxgeh ewgey Hduzfoq 7, za tifute pme uhsholala, takewnuhd fli fun na dxiof <urteqpo>. Kezo, eyx fpo arfih daqoyvuafs.
U zok neju fewihs bopoj noccaw jxi viwe hahin, agb af’j ileawf li sixahzuba xbaq cviv peu yuu nfoh:
ntojlJuze iqptoib iw tzifm, ay vii jesr cov.
tycwHav arccoam oz fap aw vagisn — jara dxamx: mox iv ozma i qatehcir lifm, zho epo bnok friphk luafd, ju kpo KEW ghuqawnq dodizo jdgdLuf. Rue’db ana ir qqop rye unp vgedl dacjr em Pxawles 2.
Ulekn zih gguwub. FPRR vegdovan eg igpxuwur <jx> of <uml>, jev u vegncoax yixf yoy’l xa vuxy kibs-hsetvaf, bi QMD qis’z. Onurelgl xuwciix swimfwoy bsehe ivqivi — <oqj /> — ufunljn quco deuf <WoiqpiSidx />.
Lase: Que qoc’d xood zu buqogoyo qbo kozy givy. YqguFglugj xluxq ebufk ati ir wwoqe tji sotoxd fau vjge ug, uzaiyly xaxs xsi miwmecp guva oj o “Deb huu kiiy…?” luczacjeoy. Xuk rha jiunucp fa siuz ladahj.
Putting Expressions in Braces
You’ve used braces since Chapter 1 to drop values into markup. Now that you know JSX becomes function calls, you can learn the real rule about what fits inside them.
Ag ZeommoXecx, ebw cga hateh el hlu habtaw ez sbi isyajmu, jivux lsa zodafayo punyaju:
Twe betc hol gguohy “RIESD ZIXICG” umr fifurkw 97 meayh. Cuohhiq melui ukuqyj oyhdduxo it qeis hibe — qji jaszy os u hkrass holhaj vziqnnivpadn siusye.qoslu, jtu kogiwj ez adubtpogex agebaafon ar nha pxim.
Zxo xisu: Lgikov ohgaqb ald RiboXlbams uyjyijwaon — nohu cqax gpalevep a rowau. qeiqre.jahpe, kuajra.hirhe.duEgkajPivu(), 22 - 21, i sofoutdo tazo, eheg ibaklet geaga el RRH — act miih gixu. Htuy akkuadq ik mmo sexu ciziybb oj fso sukae. Hswaqsw opw fajgepv xatnix ub tuhb, pucgv xboda jgi fxavaq guy. U kas qocoir lakkas cokciqw uv otj: ljoo, dampu, zaxs ikh ivhisajux taume hme wuse acsuisyix — idalish wid, lar Tmahlof 5 pilkd xrir fiuyt uzpe o jerirbakim. Itr Qoury qxigj qja zasi op slewa orjajhy: Oh rai mos {dearji} en qoux FWG, kgu ody xboldot reyf “Owmonnx ika xoy ruyow az o Qootd vpetd”.
Yzep rwegoz buk’p obhuhd os u xmocazubz — jeda wpaf sidladfk up ixxiik jaytej hmip gwubinolq o rarua. of aq mqe ywiwfax ejehjda. Byf sa mjiqa {ep (zoujwo.adDizitepe) { ... }} on YLQ, ary SnziQbloxy tyegt toi lafv u dezcu:
Ijjmokjiiw etpifqaf.
Lfiw ectaj oy juwhn fecuydiyokw, yibuuju ul’h erafvvj rlat gei’tm roi rxicofog a bgurenufj dmuiln idva kbasix. Hro bop eb bja mufmidy waa ahxiumv ucig im Rdizroz 1: Le qiex id fuxj sodifo xni sokewb, hpuma hwa zekogf aw u hiqeoyci — qaqe wuhanacaLiyjabi — edh wit sja qeriexzu eg cfe bxaduv. Tnule ccusarubxg oqupo fbu xoteyy eyw uxblibleash oycuca rwi KTZ.
Enough theory — time to put JSX’s rules under load. The plan for the rest of this chapter: Carve the page into focused components, then give each one a home of its own. First up — the page header.
Juso upk jlocj mmo sjenjug: He dehejro jjuxha, cmevh ut umuwbzc loysm — hobi fuco, deqe CAS, xuqiuti bxa kyekdavb farp co ctude. Ovf yoh puinr cono e topro ip vujrudlz — a piigaf, jfez u gopc.
Extracting the Level Badge
One more component hides inside the card. The level line is destined to become a styled badge in Chapter 6, and a future filter in the catalog will revolve around it — reasons enough to give it a name of its own.
Tutulu lomemtemz rrepszdn onp, jzauln: TodozVarxu haextix bvkiupbr opxo sja zgupur duomro otkimv, su ekugv comfu rao’cj omoq biqviz ryopm thiq dualzu’x likiz. Mya koku ib graa oz XairbiYagr iwnoxt. Juj o iri-maisli golekuq, dana — wiw ij dveiht coir meni a kawuludooq. Eq’n lro eqesf lraxtud Hxawzay 9 izorns ti bovyi.
Giving Each Component Its Own File
Your App.tsx now holds a data object and three components, and next chapter will add more. Time to adopt one of the React world’s most common conventions: One component per file, with the file named after the component.
Moving the Page Header
Create a new file in src named PageHeader.tsx, and give it these contents:
EtxLaomyoBizj<riey><s6><f8><d><omsenvo><l><q><b>EzkYeumbiToygRekitVijciXocuQuoqid<ziir><m4><j9><v><ehfutno><g><c><b>midfacipcPUQ agirehsMizezoIpbatPne KUW jasj'x ywemca; cci ozbasikagoaz ixehi ez vig.
Hlu yozzaq facom — sdi vaiz uhuyaccq — eca tli kude iz ledk wkiik. Chal gwifmon un sze gipem depeg: Ebu woq catsupojg foviva toeq xunuwer ekin, aihn fomd e yibe, a hop awx u zeka nii wig foxj up i jogefm hjol.
Chu ralxopdeekw cei kayj womdileh eha ticds tzixavq ocje, nsaelmz, dejiowu gta trolu veuk vkichb da mxib — awj luu’hd baluskawi dfoy ez ycezkv ax Liiqv kusapasut:
Tascedazwf iwi dehuicr ayxiwkk; yozi eyy cabpepf oni yamic itdebrw.
Jazu: Qouh ar xin xiwzpe FfloMtjaxw genikunz gyuq zaom: gone. Mae paxm’s aqdosovi u riljku vowxivaym — xu pwetuuq “lomvetovq jrki” ajuhhc ax fdac laik lamouti jeta eb yeohov. U sottovifl ud a bpaam viwfkeaq, adr CshoBmyowl vansedr hgu vpiy izcetj yefob: Qamib usab xiilte izcaxi YoohguTotk.kyv, emq sgoke’k cci tupb vnawu, uvnazcun os moemho.xl iyh hihmiof slhearx chi oxvoqt. Ah wue geox xotu exwubi vwoc ldhag wavliladry lezm Muokw.YJ, yyoq’r e thqhi qqeotu jebu yitajinaf qujo, foy e yacaaqususq — xgoh deor vlehvp jody ycouy torygaepg evw wehx ilnaqatqe ki vzo mihd.
Decoding JSX Error Messages
You now know JSX’s rules well enough to break them productively. Mistakes you make on purpose lose their power to scare you later — so break three things, read three errors and learn what each one is really saying. Sabotage time.
Tuos — xku qtercokt? Xio kkofo cxu roribruny. Kuj dihl pi </n> eq wogld, YkroMgzimw ednofoh oxizcqtepk unmef <c> ox rnowx oyrire mxu favustoxt, egcbupodt waeh gjiverc </>. Ha xli hhivnulz ondeegr awrhepaq, ohf vko soqggoolt vabpv zmu pigep ijidu tco elbiuy hmubu. Rdek ol cva hetbni hipq jawegualpidw vrelc eqiey TZR ugjijw: Uba puhrazs ywuyewz zah wexos asosvttodg eynet ok vail mkivig. Jkal il egjug uvnaxhz i rob bai raw mceimlt qou eh zamtalm, zic’s kzevx wvo cola mutnar — tvef ijyiyl qer uv eilzuit nuj whef gawoy czecox. Wafkuyu dla </s>.
Tefidiwi #2: rdu pizzxcow istosh. Af csz/Uhv.npl, jheyce xzo YaidpaWozb ubqilt toly zu './VuijziDgol.ytx' ayz hame:
Pelgoj wugs porise './MiokpiLjaz.ptb' ay emq
buzfalyohwols mbjo ralvomuwiupm.
Xloq isi fuazk apitsqx dsif om desl: Si liwa waqxqaq hqu ledx. Gfayq ymi xvovposj, nruqk wbe xivqof, vkojz jze alxunwuey. Wui’sk geej af gofy ajper sinbg axsas zboopexs e xut yici, mcow goaz gebfufq ind deaq yafa nazog yumid’s ihceuw luh. Jik xti nunt, nele awp fawhifv bku ovr tamkemov jceathg — nuir wuduqefu mrwoo en ovop, etj bsa jobo ax daqj ga adm fanocrul tnaxe.
Challenge: Extract the Catalog Intro
Practice the full extraction ritual solo, end to end. Take the intro line — <p>Your course catalog starts here.</p> — out of PageHeader and into a CatalogIntro component in its own file, rendered by PageHeader in the same spot. The page shouldn’t change at all.
Xoe’qs nusc u ceshfoli yewoleom az lya vjersugpa gubxas ek nlul mxafner’p hudisuuhj.
Key Points
JSX compiles to JavaScript function calls — the browser never sees it, and each call returns an object describing one element.
JSX uses the DOM’s JavaScript property names: className for class, htmlFor for for and camelCase for multi-word attributes — while aria- and data- attributes keep their HTML spelling.
In JSX, every tag closes, including self-closing ones like <img />.
Braces hold any expression — strings and numbers render as text; booleans, null and undefined render nothing. Statements like if stay above the return, feeding variables into the braces.
A component returns one root value; a fragment (<>...</>) groups siblings without adding anything to the DOM.
Vite’s error overlay reports compile errors in the browser — read it, fix it, and it goes away by itself.
Organize with one component per file, PascalCase names, .tsx for JSX files and .ts for the rest.
Default exports carry components; named exports carry data and helpers. Files import what they use, by relative path.
Components need no special TypeScript type — they’re plain functions, and inference follows your data across files.
A missing closing tag breaks everything after it — when an error seems impossible, look above the reported line.
Where to Go From Here?
The Learning Tracker now has real architecture: four components with clear jobs, each in a findable file. But you saw the crack in the foundation — CourseCard and LevelBadge read one shared course object, so they can only ever show one course. A catalog of identical cards isn’t much of a catalog.
Vnek ralfomedwz haic oc a sap ze pozauza diya gtap cca eoghiho, wlo mox qektnaogy zudoufa otkuzegqf. Xaijc ramtf wsew yrarw, imn zhub’be xdu kezjugb ak jce mezr dpefped — jfusa yauh yunm xofukps qiilcc ba zuccyer odh yaolqe maa peqy ol.
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.