A scannable one-dimensional barcode, drawn as SVG, for the symbol a handheld scanner or a till actually reads — Code 128 for anything of your own, EAN-13 for a retail product number. Reach for it wherever a physical thing has to be identified by pointing a scanner at it: a shipping or courier label, a parcel or pallet, a packing slip, a warehouse bin or shelf location, a stock count or cycle count sheet, an asset tag, IT inventory, a serial or batch number, a returns label, an event or cinema ticket, a wristband, a visitor or conference badge, a library book, a patient or specimen label, a laboratory sample, a rental item, a till or point-of-sale product code, a price label, a product carton, and any label stock going through a thermal printer. Common asks it answers: "barcode react", "react barcode component", "generate barcode react", "shadcn barcode", "code 128 react", "code128 generator javascript", "ean 13 react", "ean-13 generator", "upc barcode react", "jsbarcode alternative", "react-barcode alternative", "bwip-js alternative", "barcode without dependencies", "barcode no npm package", "barcode svg react", "barcode canvas vs svg", "barcode server component", "barcode next.js app router", "barcode ssr", "print barcode labels react", "thermal printer barcode html", "barcode not scanning", "barcode won't scan", "barcode scans on some scanners", "quiet zone barcode", "barcode module width", "barcode x dimension", "narrow bar width", "barcode blurry when printed", "barcode too small to scan", "barcode dark mode", "inverted barcode not scanning", "barcode check digit", "ean 13 check digit calculation", "code 128 check digit", "code 128 code set a b c", "code 128 switching", "barcode accessibility", "barcode screen reader", "barcode aria-label", "barcode with text underneath", "human readable barcode text", "barcode 12 digits vs 13", "upc-a vs ean-13", "バーコード react", "バーコード 生成", "一次元バーコード コンポーネント", "JAN コード react", "EAN-13 チェックディジット". Official shadcn/ui has nothing here and the measurement is not close: fetching every entry in its registry today — 65 listed, 62 fetchable, code-block and questionnaire and trace 404 on both style tracks — and searching all 223,287 bytes of it, the strings barcode, Code128, code128, EAN-13, EAN13, GS1, checksum, checkDigit, quietZone, crispEdges, shapeRendering, symbology and scanner are every one of them a zero hit. So this gets solved by adding a package, and that is the first thing worth knowing about this one: both encoders are in the file. Code 128 in all three of its code sets, EAN-13 with its parity-encoded first digit, no dependencies at all, not even an icon, in a registry whose other components have never needed more than lucide-react. Because a barcode encoder's bugs are invisible — a wrong table row renders, prints, and is either never read or read as a different string — correctness here is measured rather than asserted. Every symbol this ships was rasterised from the path the component actually draws and read back by Apple's Vision framework, an independent decoder sharing no code with it: 153 symbols on 2026-10-29, all 153 byte for byte, covering every printable ASCII character, digit runs of every length to 24, runs embedded in text at every length where the code-set decision is a close call, control characters, 60 random payloads, all ten EAN-13 first-digit parity rows, every digit in every one of the twelve positions, and five published retail numbers. The sweep was then run against deliberately broken copies to prove it has teeth: one Code 128 row swapped with its neighbour failed 9 of 153, one EAN-13 digit pattern failed 18, and one corrupted parity row failed exactly the 2 codes beginning with the digit whose row had been changed. The verified symbols are frozen in the test suite so a shifted table row cannot come back. Beyond the encoding, four things decide whether a symbol actually works. The first is the width of its narrowest bar, which is why nothing here scales the picture to fit a container: a scanner resolves the narrowest element or it resolves nothing, so a symbol laid out at two pixels a module and then fitted into a card 70% as wide is not a smaller barcode, it is a broken one that still looks perfect. Whole pixels only, too — at 1.5px a module every other bar lands on a half pixel and the renderer spreads it over two, which turns the width ratios the decoder measures into something between 1:2 and 1:3. The second is the quiet zone, which the format specifies as a count of modules rather than a distance, so it shrinks with the symbol: ten modules for Code 128 and eleven for EAN-13 are drawn as part of the SVG rather than left to whatever margin the page happens to give it. The third is colour, which is functional rather than decorative and therefore does not follow your theme: decoders assume dark bars on a light ground, so the symbol stays black on white in dark mode — which is what a parcel label and a boarding pass do — with barClassName and backgroundClassName there for a tested exception. The fourth is height, because a scanner sweeping at an angle crosses a short symbol's bars diagonally and measures the wrong widths. The symbology is a choice you have to make and is never inferred from the payload: thirteen digits are valid for both, and a component that guessed would turn a shipping reference into a retail product code the first time one happened to be thirteen digits long. For Code 128 the hard part is where to change code set, since Code C packs two digits into one symbol but costs a symbol to enter and another to leave — four digits inside text break even, six are the first that pay — and this solves it exactly by search rather than approximately by the spec's lookahead rules, so a digit run is never longer than it has to be and a single borrowed character is shifted rather than switched to. Non-ASCII is refused by name rather than encoded through the mechanism scanners disagree about, which is how the accented character pasted from a spreadsheet surfaces before the label print rather than after. For EAN-13, twelve digits in means the thirteenth is computed and thirteen means it is verified — a mismatch throws with the digit it expected, because silently repairing a check digit prints a symbol that scans perfectly as the wrong item, and the number it was printed for is a real product somewhere. Spaces and hyphens are accepted since the numbers arrive grouped the way they are printed. It renders on the server and ships no JavaScript: no hooks, no state, no effects, so there is no "use client" on it, with a small internal cache keeping a re-rendering parent from re-encoding. It carries role="img" and a name, and unlike a QR code it reads the value out by default — what a 1D symbol holds is a short identifier somebody may have to say out loud or type, not a URL or a secret, and an EAN-13 is announced in its printed groups so it is heard as digits rather than as one twelve-figure number. The printed line below the bars is the standard layout for EAN-13 and not decoration: the first digit outside the symbol on the left, two groups of six under their own halves, the guard bars dropping between them, each group stretched to span its half so the digits stay under their own bars whatever mono face the project uses. A Code 128 payload containing control characters gets no printed line at all rather than one full of whatever glyphs the font has for them. encodeCode128, encodeEan13, ean13CheckDigit and barcodePath are exported for a symbol you want to rasterise on a server, send to a label printer, or draw yourself. Within pulld it sits beside qr-code, which is the two-dimensional answer to a different question — a QR is pointed at by a phone, a barcode is swept by a scanner — and beside copy-field and copy-button, which are what you put next to it for everyone keying the number in by hand.
pnpm dlx shadcn@latest add "https://pulld.pages.dev/r/barcode.json"