diff --git a/packages/volto-govrs-ds/news/23.feature b/packages/volto-govrs-ds/news/23.feature
new file mode 100644
index 0000000..0d15831
--- /dev/null
+++ b/packages/volto-govrs-ds/news/23.feature
@@ -0,0 +1,2 @@
+Implementação do componente Tag dispensáveis ( Default) e Variantes:
+Tag Texto, Tag Persistente, Tag Status, Tag Icone e Tag de Contagem(@Gabriel-SAbreu)
\ No newline at end of file
diff --git a/packages/volto-govrs-ds/src/components/Tag/Tag.stories.jsx b/packages/volto-govrs-ds/src/components/Tag/Tag.stories.jsx
new file mode 100644
index 0000000..4d276ea
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/Tag.stories.jsx
@@ -0,0 +1,238 @@
+import Tag from './index';
+import Persistente from './variants/Persistente';
+export default {
+ title: 'Components/Tag',
+ component: Tag,
+};
+
+export const TagDocs = () => (
+ <>
+
+
Tag - Documentação
+
+ O componente Tag permite escolher a variante através da
+ prop variant. Isso facilita a utilização quando se deseja
+ alternar entre diferentes tipos de tags dinamicamente.
+
+
+ Tag de Interação
+
+ Possuem uma ação ao serem clicadas/tocadas. De acordo com o tipo de
+ interação podemos ter tags interativas dispensáveis e persistentes.
+
+ Tags aceitam as props content, disabled e{' '}
+ showIcon
+
+ Dispensáveis
+
+
+
+
+
+
+
+ {` `}
+ {` `}
+
+
+
+ Ao utilizar a prop showIcon, a tag não exibe o ícone.
+
+
+
+
+
+
+
+
+ {` `}{' '}
+
+ {` `}
+
+
+ Texto
+
+ A tag pode não possuir nenhum tipo de interação, serrvindo apenas para
+ exibição de um texto, nesse caso, pode possuir icone e texto ou somente
+ texto. Optando pela segunda opção utilizasse a prop showClose{' '}
+ como false.
+
+
+
+
+
+
+
+
+
+
+ {` `}{' '}
+
+ {` `}
+
+ {` `}
+
+ {` `}
+
+
+ Persistentes
+
+ Tags persistentes não podem ser dispensadas, apenas indicam um estado ou
+ categoria.
+
+
+ As props content, disabled e{' '}
+ showIcon são aceitas.
+
+
+
+ {' '}
+ ATENÇÃO: nas tags persistentes que serão selecionadas por padrão,
+ utilize a prop defaultChecked juntamente com a prop{' '}
+ disabled.
+
+
+
+
+
+
+
+
+ {` `}
+ {``}
+
+ {`
+
+
+ Persistente — Grupo (radio)
+
+ Variação para seleção única entre várias tags. Cada tag precisa ter um{' '}
+ id único.
+
+
+ Para selecionar uma tag por padrão, utilize a prop{' '}
+ defaultSelected com o valor do id da tag
+ desejada.
+
+
+
+
+ {``} {' '}
+
+ {` `}
+
+ {` `}
+
+ {` `}
+
+ {``}
+
+
+ Status
+
+ Tags de status são utilizadas para indicar estados ou categorias
+ específicas. Elas não possuem interação de clique.
+
+
+
+
+
+
+
+ {` `}{' '}
+
+ {` `}
+
+ {` `}
+
+
+
+ Podem ser usadas com Label ou apenas com a superfície circular. {' '}
+ Para realizar a escolha utilizar a propLabel vazia ou com o
+ mesmo conteúdo da prop status.
+
+
+
+
+
+
+
+ {` `}
+ {` `}
+
+ {` `}
+
+
+ Icone
+
+ Tags de icone possuem a mesma ideia das tags texto, porém utilizando
+ apenas icone
+
+
+ As props ico pode ser utilizada para especificar qual icone
+ será exibido.
+
+
+
+
+
+
+ {` `}
+ {` `}
+
+
+ Contagem
+
+ Tags de contagem são utilizadas para exibir um número ou valor associado a
+ uma tag.
+
+
+ Se o valor for maior que 999, será exibido como "999+". Os valores são
+ atribuidos através da prop label.
+
+
+
+
+
+
+
+
+
+ {` `}
+ {` `}
+ {` `}
+ {` `}
+ {` `}
+
+ >
+);
diff --git a/packages/volto-govrs-ds/src/components/Tag/index.jsx b/packages/volto-govrs-ds/src/components/Tag/index.jsx
new file mode 100644
index 0000000..bbdb0f5
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/index.jsx
@@ -0,0 +1,28 @@
+import Default from './variants/Default.jsx';
+import Persistente from './variants/Persistente';
+import Status from './variants/Status';
+import Icone from './variants/Icone';
+import Contagem from './variants/Contagem';
+
+const VARIANTS = {
+ default: Default,
+ persistente: Persistente,
+ persistenteGroup: Persistente.Group,
+ status: Status,
+ icone: Icone,
+ contagem: Contagem,
+};
+
+export default function Tag({
+ items = [],
+ variant,
+ itemKey = (i) => i.id,
+ className = '',
+ ...rest
+}) {
+ const v = variant || 'default';
+ const Variant = VARIANTS[v] || Default;
+ return (
+
+ );
+}
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.jsx b/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.jsx
new file mode 100644
index 0000000..162d94a
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.jsx
@@ -0,0 +1,19 @@
+import './Contagem.scss';
+
+const Contagem = ({ label }) => {
+ const n = Number(label);
+ const displayLabel = Number.isFinite(n)
+ ? n > 999
+ ? '999+'
+ : String(n)
+ : label;
+ return (
+ <>
+
+ {displayLabel}
+
+ >
+ );
+};
+
+export default Contagem;
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.scss b/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.scss
new file mode 100644
index 0000000..61beba2
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Contagem.scss
@@ -0,0 +1,14 @@
+.govrs-tag-contagem {
+ display: inline-flex;
+ min-width: 24px;
+ min-height: 24px;
+ align-items: center;
+ justify-content: center;
+ padding: 1px 7px 4px 7px;
+ border: 1px solid #fff;
+ border-radius: 999px;
+ background-color: #d54309;
+ color: #fff;
+ font-size: 0.875rem;
+ gap: 8px;
+}
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Default.jsx b/packages/volto-govrs-ds/src/components/Tag/variants/Default.jsx
new file mode 100644
index 0000000..42991d8
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Default.jsx
@@ -0,0 +1,87 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import './Default.scss';
+
+function CarIcon() {
+ return (
+
+
+
+ );
+}
+
+function CloseIcon() {
+ return (
+
+
+
+ );
+}
+const Default = ({
+ disabled = false,
+ showClose = true,
+ content = 'Tag Default',
+ showIcon = true,
+}) => {
+ const [visible, setVisible] = useState(true);
+
+ const handleClose = () => {
+ if (disabled) return;
+ setVisible(false);
+ };
+
+ if (!visible) return null;
+
+ return (
+ <>
+
+ {showIcon && }
+ {content}
+
+ {showClose && (
+
+
+
+ )}
+
+ >
+ );
+};
+
+Default.propTypes = {
+ disabled: PropTypes.bool,
+ content: PropTypes.node,
+ showClose: PropTypes.bool,
+ showIcon: PropTypes.bool,
+};
+
+Default.defaultProps = {
+ disabled: false,
+ content: 'Tag Default',
+ showClose: true,
+ showIcon: true,
+};
+
+export default Default;
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Default.scss b/packages/volto-govrs-ds/src/components/Tag/variants/Default.scss
new file mode 100644
index 0000000..a54c1c3
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Default.scss
@@ -0,0 +1,86 @@
+.govrs-tag {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 4px 8px;
+ border: none;
+ border-radius: 4px;
+ background-color: #1a7235;
+ color: #fff;
+ gap: 8px;
+
+ &:not(.disable):hover {
+ background: linear-gradient(
+ 0deg,
+ rgba(255, 255, 255, 0.3) 0%,
+ rgba(255, 255, 255, 0.3) 100%
+ ),
+ #1a7235;
+ }
+ &:not(.disable):active {
+ background: linear-gradient(
+ 0deg,
+ rgba(255, 255, 255, 0.65) 0%,
+ rgba(255, 255, 255, 0.65) 100%
+ ),
+ #1a7235;
+ }
+
+ > button {
+ padding: 0;
+ border: none;
+ background-color: transparent;
+ color: #fff;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+
+ &-group {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ }
+}
+
+.disable {
+ cursor: not-allowed;
+ opacity: 0.45;
+ > button {
+ pointer-events: none;
+
+ &:hover,
+ &:active {
+ background-color: #1a7235;
+ cursor: not-allowed;
+ }
+ }
+}
+
+/* Layout para grupos de tags (ex.: Persistente.Group) */
+.govrs-tag-group {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+/* Foco visível para acessibilidade */
+.govrs-tag:focus-visible {
+ border-color: rgba(10, 97, 41, 0.9);
+ box-shadow: 0 0 0 6px rgba(10, 97, 41, 0.12);
+ outline: none;
+}
+
+.checked {
+ background-color: #279b4a;
+}
+
+// Estilo para exibir utilização dos blocos de código nos stories
+.showCode {
+ padding: 12px;
+ border-radius: 4px;
+ margin-top: 8px;
+ background: #f7f7f7;
+ overflow-x: auto;
+}
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Icone.jsx b/packages/volto-govrs-ds/src/components/Tag/variants/Icone.jsx
new file mode 100644
index 0000000..b00f3f7
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Icone.jsx
@@ -0,0 +1,68 @@
+import PropTypes from 'prop-types';
+import './Icone.scss';
+
+function SearchIcon() {
+ return (
+
+
+
+ );
+}
+
+function CarIcon() {
+ return (
+
+
+
+ );
+}
+
+const Icone = ({ ico = 'search' }) => {
+ const renderIcon = () => {
+ switch (ico) {
+ case 'search':
+ return ;
+ case 'car':
+ return ;
+ default:
+ return null;
+ }
+ };
+
+ return (
+ <>
+ {renderIcon()}
+ >
+ );
+};
+Icone.propTypes = {
+ ico: PropTypes.oneOf(['search', 'car']),
+ message: PropTypes.string,
+ children: PropTypes.node,
+ outline: PropTypes.bool,
+};
+
+Icone.defaultProps = {
+ message: null,
+ children: null,
+ outline: false,
+};
+
+export default Icone;
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Icone.scss b/packages/volto-govrs-ds/src/components/Tag/variants/Icone.scss
new file mode 100644
index 0000000..23fe11f
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Icone.scss
@@ -0,0 +1,15 @@
+@import '../../../theme/variables.scss';
+
+.govrs-tag-icon {
+ display: inline-flex;
+ max-width: 40px;
+ min-height: 40px;
+ align-items: center;
+ justify-content: center;
+ padding: 12px;
+ border: 1px solid #fff;
+ border-radius: 50%;
+ background-color: Magenta;
+ color: #fff;
+ gap: 12px;
+}
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.jsx b/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.jsx
new file mode 100644
index 0000000..0728a2c
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.jsx
@@ -0,0 +1,187 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import './Persistente.scss';
+
+function CarIcon() {
+ return (
+
+
+
+ );
+}
+
+function CheckIcon() {
+ return (
+
+
+
+ );
+}
+
+const Persistente = ({
+ disabled = false,
+ content = 'Tag Persistente',
+ checkIcon = true,
+ showIcon = true,
+ checked: checkedProp,
+ defaultChecked = false,
+ onChange,
+}) => {
+ const [internalChecked, setInternalChecked] = useState(defaultChecked);
+ const isControlled = checkedProp !== undefined;
+ const checked = isControlled ? checkedProp : internalChecked;
+
+ const handleCheck = () => {
+ const newChecked = !checked;
+ if (!isControlled) setInternalChecked(newChecked);
+ if (typeof onChange === 'function') onChange(newChecked);
+ };
+
+ return (
+ <>
+ {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ handleCheck();
+ }
+ }
+ : undefined
+ }
+ tabIndex={disabled ? -1 : 0}
+ aria-pressed={checkIcon ? checked : undefined}
+ >
+ {showIcon && }
+ {content}
+ {checkIcon && checked && }
+
+ >
+ );
+};
+
+Persistente.propTypes = {
+ disabled: PropTypes.bool,
+ content: PropTypes.node,
+ checkIcon: PropTypes.bool,
+ showIcon: PropTypes.bool,
+ checked: PropTypes.bool,
+ defaultChecked: PropTypes.bool,
+ onChange: PropTypes.func,
+};
+
+Persistente.defaultProps = {
+ disabled: false,
+ content: 'Tag Persistente',
+ checkIcon: true,
+ showIcon: true,
+ defaultChecked: false,
+ onChange: undefined,
+};
+
+// Group variant: quando radio=true, gerencia seleção única (radio-like). Se radio=false, renderiza filhos sem gerenciar.
+function Group({
+ children,
+ radio = false,
+ defaultSelected = null,
+ selected: selectedProp,
+ onChange,
+ allowUnselect = true,
+ ariaLabel,
+}) {
+ const [selected, setSelected] = useState(defaultSelected);
+ if (!radio) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ // const [selected, setSelected] = useState(defaultSelected);
+ const isControlled = selectedProp !== undefined;
+ const current = isControlled ? selectedProp : selected;
+
+ const handleChildChange = (id, newChecked) => {
+ if (!newChecked && allowUnselect) {
+ if (!isControlled) setSelected(null);
+ if (typeof onChange === 'function') onChange(null);
+ return;
+ }
+ if (newChecked) {
+ if (!isControlled) setSelected(id);
+ if (typeof onChange === 'function') onChange(id);
+ }
+ };
+
+ return (
+
+ {React.Children.map(children, (child) => {
+ // se o child não tiver id, não alteramos
+ const id = child.props && child.props.id;
+ if (!id) return child;
+ return React.cloneElement(child, {
+ checkIcon: true,
+ checked: id === current,
+ onChange: (newChecked) => handleChildChange(id, newChecked),
+ role: 'radio',
+ 'aria-checked': id === current,
+ className: 'govrs-tag-group-active',
+ });
+ })}
+
+ );
+}
+
+Group.propTypes = {
+ children: PropTypes.node,
+ radio: PropTypes.bool,
+ defaultSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ selected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ onChange: PropTypes.func,
+ allowUnselect: PropTypes.bool,
+ ariaLabel: PropTypes.string,
+};
+
+Group.defaultProps = {
+ radio: false,
+ defaultSelected: null,
+ onChange: undefined,
+ allowUnselect: true,
+ ariaLabel: 'Tag group',
+};
+
+Persistente.Group = Group;
+
+export default Persistente;
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.scss b/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.scss
new file mode 100644
index 0000000..4d5b7c9
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Persistente.scss
@@ -0,0 +1,20 @@
+/* Styles específicos para a variante Persistente */
+
+/* Layout para grupos de tags (ex.: Persistente.Group) */
+.govrs-tag-group {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+/* Estado visual quando a tag está marcada */
+.govrs-tag.checked {
+ background-color: #279b4a;
+}
+
+/* Foco visível para acessibilidade (aplicável a tags persistentes) */
+.govrs-tag:focus-visible {
+ border-color: rgba(10, 97, 41, 0.9);
+ box-shadow: 0 0 0 6px rgba(10, 97, 41, 0.12);
+ outline: none;
+}
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Status.jsx b/packages/volto-govrs-ds/src/components/Tag/variants/Status.jsx
new file mode 100644
index 0000000..4a6d25a
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Status.jsx
@@ -0,0 +1,23 @@
+import PropTypes from 'prop-types';
+import './Status.scss';
+const Status = ({ status = 'online', Label }) => {
+ const classes = ['govrs-tag-status', `govrs-tag-status--${status}`];
+ return (
+ <>
+
+
+ {Label}
+
+ >
+ );
+};
+
+Status.propTypes = {
+ status: PropTypes.oneOf(['Online', 'Offline', 'Ausente']),
+};
+
+Status.defaultProps = {
+ status: 'online',
+};
+
+export default Status;
diff --git a/packages/volto-govrs-ds/src/components/Tag/variants/Status.scss b/packages/volto-govrs-ds/src/components/Tag/variants/Status.scss
new file mode 100644
index 0000000..8cb2efc
--- /dev/null
+++ b/packages/volto-govrs-ds/src/components/Tag/variants/Status.scss
@@ -0,0 +1,27 @@
+@import '../../../theme/variables.scss';
+
+.govrs-tag-status {
+ display: inline-flex;
+ width: 24px;
+ height: 24px;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid var(--gray-2);
+ border-radius: 50%;
+ font-family: $font-family-base;
+ gap: 8px;
+}
+.govrs-tag-status--Online {
+ background-color: var(--green-cool-vivid-50);
+ color: #fcfcfc;
+}
+
+.govrs-tag-status--Offline {
+ background-color: var(--red-vivid-50);
+ color: #fcfcfc;
+}
+
+.govrs-tag-status--Ausente {
+ background-color: var(--gold-vivid-20);
+ color: #fcfcfc;
+}