# react-share and the two prop names that both mean title

> Share buttons for 24 networks with no SDK loading and tree-shakeable ES module output, published as a dual CommonJS and ESM package with only dist shipped. Its metadata still advertises share counts that the feature list has deprecated, and its email button quietly drops two of the shared props.

**nygardk/react-share** — Social media share buttons and share counts for React

- Repository: https://github.com/nygardk/react-share
- Stars: 2,815 · Forks: 439
- Language: TypeScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/nygardk-react-share

## The metadata still advertises share counts the feature list deprecated

Both one-line descriptions promise the same pair of things. The repository summary says social media share buttons and share counts for React, and the manifest description says the same thing with a full stop, and the keyword list still ends with count. The feature list, in the same file, presents share counts with the word deprecated attached and a link to its own section. So the headline a visitor reads on a package page and on a repository listing advertises a capability the documentation has retired, and the only place the two meet is the feature list. The rest of that list is the reason the package exists at all: no external script loading, meaning no dependency on vendor SDKs, tree shaking with ES modules, a popup share window, and 24 networks of buttons with icons bundled in, plus support for passing your own icon as children.

## Two props both mean title, and neither is an accessible name

Every network has its own share title prop, named title, and the shared list has a separate htmlTitle that sets the native title attribute on the button element underneath. The file says why the names are different: the native attribute uses htmlTitle so it does not collide with the network share props named title. The example makes the split explicit:

```jsx
<XShareButton
  title="Share title sent to X"
  htmlTitle="Native button tooltip"
  url={shareUrl}
  aria-label="Share on X"
>
  <XIcon size={32} round />
</XShareButton>;
```

The third name in that block is the one that matters for accessibility. Icon-only buttons need an accessible name, and the file says htmlTitle only sets the tooltip and is not used as the accessible name, so aria-label or aria-labelledby is the only route. Buttons pass through aria-label, aria-labelledby, aria-describedby, name and data-* unchanged, which is what makes that possible.

## The email button is not a popup button and drops two shared props

The shared props fall into three tiers, and the tier boundaries are where the surprises are. Required on everything are children and url. Optional on all share buttons are beforeOnClick, disabled, disabledStyle with a default opacity of 0.6, htmlTitle, onClick, onShareWindowClose, resetButtonStyle defaulting to true, and the popup dimensions and position, where position is either windowCenter or screenCenter. Optional only on popup-based buttons is openShareDialogOnClick, default true. EmailShareButton is not one of them: it uses mailto: navigation, so the file says it does not expose openShareDialogOnClick, and the shared list separately notes that onClick is not exposed by EmailShareButton either. Instead it takes subject, body and its own separator, defaulting to a single space.

## Twenty-four networks, and two of them are documented out of order

The feature list runs Facebook before Facebook Messenger. The API sections run FacebookMessengerShareButton before FacebookShareButton, so a reader scanning for the button they already know by name meets the Messenger one first. The list itself covers Bluesky, Email, Facebook, Facebook Messenger, Gab, Hatena, Instapaper, Line, LinkedIn, LiveJournal, Mail.Ru, Odnoklassniki, Pinterest, Pocket, Reddit, Telegram, Threads, Tumblr, Viber, VK, Weibo, Whatsapp, Workplace and X. The per-network sections as they stand here end inside the InstapaperShareButton heading, on the first three letters of the word Optional, so the props for the networks after Instapaper are not written down in this copy of the file. One link also points at an older name: the Odnoklassniki entry jumps to an anchor named for the Ok component.

## The suite runs twice, once against the built package

There are three test scripts and two validation tools. test runs vitest, test:coverage adds coverage, and test:dist points vitest at a second configuration, so the same suite is executed against the built distribution and not only against the source. lint-package is the other half of that idea: it runs publint and the arethetypeswrong CLI against the packed tarball, which checks the published entry points rather than the source tree. check-types type-checks two projects, the library and the demo, and lint covers src and demo. What the scripts do not do is gate the publish on any of it: prepublishOnly runs the build and nothing else, and release is the build followed by changeset publish, with a .changeset directory at the root to collect the version notes.

## One dist folder, two module formats, and no side effects

The packaging is what makes the tree-shaking claim work. The manifest is type module, ships a CommonJS main at dist/index.cjs, an ES module at dist/index.js, an exports map routing import to one and require to the other, type declarations at dist/index.d.ts, and sideEffects set to false so a bundler can drop what you did not import. Only dist is published. The build is Vite, with a second config for the demo, and there are four TypeScript configurations, a base, a build, the demo and the default. The demo lives in its own directory with its own CSS, entry point, HTML file and a declaration file for its assets, and the README links a deployed copy of it on a Netlify address while also telling you to run it locally with npm install and npm run demo.

## No SDK loading is a claim the dependency list quietly contradicts

The first feature bullet promises no external script loading and no dependency on SDKs, and the mechanism is a popup window whose size and position you control, with a callback for when it closes. The dependency list tells a slightly different history. Among the development dependencies there is a type package for jsonp, the technique for loading a script tag and reading data back from it, which is precisely what a no-script-loading implementation would not need. Development-only types outlive the behaviour they were written for, so this is a leftover rather than a dependency, but it is the kind of leftover that tells you the library once worked a different way. The rest of the root is ordinary: an .nvmrc, a .prettierrc, an eslint flat config, a .vscode directory, a docs directory, AGENTS.md, and an example image at the top level.

## Conclusion

react-share fits a React application that wants share buttons it can style and tree-shake without pulling in a vendor SDK, and its accessibility guidance is more careful than most button libraries of its size. Four things to check before you adopt it. Two props both look like a title, so read the names carefully: title goes to the network, htmlTitle sets the native tooltip, and neither is an accessible name, which must come from aria-label or aria-labelledby. The email button is not a popup button, so onClick and openShareDialogOnClick do not exist on it and the popup props do nothing. The package metadata still advertises share counts that the feature list marks deprecated. And when you need a share network that is not in the list, nothing in the repository suggests an alternative library, so you would be assembling those buttons yourself.

## FAQ

### react-share alternative

The repository names no alternative library. What it offers is share buttons for 24 networks with icons included, a popup share window, no dependency on vendor SDKs, tree shaking with ES modules, and a share-count feature that is marked deprecated.

### How do I make react-share buttons accessible?

Every share button renders a native button element and passes through aria-label, aria-labelledby, aria-describedby, name and data-* attributes. Icon-only buttons need an accessible name from aria-label or aria-labelledby, because htmlTitle only sets the native title attribute and is not used as the button's accessible name.

### Which React versions work with react-share 5?

The compatibility table maps major version 5 to React 17, 18 and 19, version 4 to ^16.3, 17 and 18, version 3.0.1 to ^16.3, version 3 to 15 and 16, version 2 to 15 and 16, and version 1 to 0.13.x, 0.14.x and 15.x.x.

### What does EmailShareButton do differently from the other buttons?

It uses mailto: navigation instead of opening a popup, so it does not expose openShareDialogOnClick or onClick, and the popup dimension and position props do not apply to it. It takes subject, body and a separator that defaults to a single space.

### How do I install react-share?

With npm install react-share. The package publishes only its dist folder, ships CommonJS and ES module entry points with type declarations, and marks itself free of side effects. A deployed demo is linked, and the same demo runs locally with npm install and npm run demo.

## Sources

- [Issues](https://github.com/nygardk/react-share/issues)
- [License: MIT](https://github.com/nygardk/react-share/blob/master/LICENSE)
- [nygardk/react-share on GitHub](https://github.com/nygardk/react-share)
- [README](https://github.com/nygardk/react-share/blob/master/README.md)
- [Releases](https://github.com/nygardk/react-share/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nygardk-react-share
