The "String" component is deprecated and will be removed

Hi,

i become the warning [@forge/react: String] Warning: The “String” component is deprecated and will be removed on the 28th of August 2025. Please use the “Text” component instead. For more information, visit: https://developer.atlassian.com/platform/forge/ui-kit/components/text/.

Im using the Text component in my forge uikit macro . i have no text in small in the code , but i use Link ? Can it be issued by the Link UI Component ?

BR
Kai

Hi Kai,

could you share some app code to help me understand the issue that you’re facing?

The warning comes from within the definition of the String component, so you could search your code base for usages of <String> and replace those with <Text>.

Cheers
Jonathan

const App = () => {

  const [tableMap, setTableMap] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const config = useConfig();

    // Function rendering Text or Link 
  function RenderTextOrLink({ children }) {
    // Prüfen, ob der Text ein Link ist (beginnt mit http, https oder www)
    if (children && (children.startsWith('http://') || children.startsWith('https://') || children.startsWith('www.'))) {
    //   Wenn der Text mit www beginnt, füge http:// hinzu
      const href = children.startsWith('www.') ? `http://${children}` : children;
      return <Link href={href}><Text>{children}</Text></Link>;
    }
    // return Text
    return <Text>{children}</Text>;
  }


  useEffect(() => {
    const fetchObjects = async () => {
      setIsLoading(true);
      if (config) {
        const pathKey = config.pathKey;
        const response = await invoke('getObjects', { pathKey });       
        
        if (response) {
          // Process the data to create table_map
          const processedTableMap = processObjectData(response);
          setTableMap(processedTableMap);
        }
      }
      setIsLoading(false);
    };
    fetchObjects();
  }, [config]);

  const processObjectData = (response) => {
    let table_map = [];
    let regex = /<p>(.+)<\/p>/gm;

    table_map.push({ label: "Company Name", value: "", users: []}); 
    table_map.push({ label: "Customer Type", value: "", users: []}); 
    table_map.push({ label: "APplus ID", value: "", users: []}); 
    table_map.push({ label: "Customer Prefix", value: "", users: []}); 
    table_map.push({ label: "Alias", value: "", users: []}); 
    table_map.push({ label: "Parent Company", value: "", users: []}); 
    table_map.push({ label: "NTS Site", value: "", users: []}); 
    table_map.push({ label: "Address", value: "", users: []}); 
    table_map.push({ label: "NTS Key Account Manager", value: "", users: []}); 
    table_map.push({ label: "NTS Account Manager", value: "", users: []}); 
    table_map.push({ label: "NTS Account Engineers", value: "", users: []}); 
    table_map.push({ label: "NTS Service Delivery Manager", value: "", users: []}); 
    table_map.push({ label: "NTS Engineering Manager", value: "", users: []}); 
    table_map.push({ label: "Change Process Obligation", value: "", users: []}); 
    table_map.push({ label: "Remote Access", value: "", users: []}); 
    table_map.push({ label: "Passwordmanager Link", value: "", users: []}); 
    table_map.push({ label: "NTS Monitor Link", value: "", users: []}); 

    try {
      
      for(let i=0; i < response["attributes"].length; i++) {
        for(let j=0; j < table_map.length; j++) {
          let current_attribute_name = response["attributes"][i]["objectTypeAttribute"]["name"];
          let current_values = response["attributes"][i]["objectAttributeValues"];
          
          if (current_values.length === 0) continue;
          
          let current_display_value = current_values[0]["displayValue"];
          let current_attribute_type = response["attributes"][i]["objectTypeAttribute"]["type"];

          if(current_attribute_name === table_map[j].label && 
            current_display_value !== undefined) {
            if(current_attribute_type === 2 && 
               response["attributes"][i]["objectTypeAttribute"]["typeValueMulti"] && 
               response["attributes"][i]["objectTypeAttribute"]["typeValueMulti"][0] === "GP_Jira"){ //User Field
              for(let k=0; k < current_values.length; k++) {
                if (current_values[k]["user"] && current_values[k]["user"]["key"]) {
                  table_map[j].users.push(current_values[k]["user"]["key"]);
                }
              }
            } else if(current_attribute_type === 0 && 
                     response["attributes"][i]["objectTypeAttribute"]["defaultType"] && 
                     response["attributes"][i]["objectTypeAttribute"]["defaultType"]["name"] === "Textarea") { //Text Area Field
              let area_content = regex.exec(current_display_value.toString());
              let area_text;
            
              //In case the Text Area is not surrounded by HTML Paragraph Tags, it outputs the raw Content of the Text Area
              if(area_content != null) {
                area_text = area_content[1];
              } else {
                area_text = current_display_value;
              }

              table_map[j].value = area_text.toString().replace(/<br>|<br\/>|<br \/>/gm, "\n").replace(/<\/p><p>/gm, "\n").replace(/&nbsp;/gm, " ");
            } else {
              table_map[j].value = current_display_value;
            }
          }
        }
      }
    } catch(err) {
      //Error code for table in case of try catch fault
      table_map = [{ label: "A critical error has occurred: " + err, value: "", users: []}];
    }

    return table_map;
  };

  // Tabellenhead definition
  const head = {
    cells: [
      {
        key: 'field',
        content: <Text weight="bold">Field</Text>,
        width: 30
      },
      {
        key: 'value',
        content: <Text weight="bold">Value</Text>,
        width: 70
      }
    ]
  };

  // Tablerow definition
  const rows = tableMap.map((element, index) => ({
    key: `row-${index}`,
    cells: [
      {
        key: `cell-label-${index}`,
        content: <Text as="strong">{element.label}</Text>
      },
      {
        key: `cell-value-${index}`,
        content: element.users.length === 1 ? (
          <User accountId={element.users[0]} />
        ) : element.users.length > 1 ? (
          <UserGroup>
            {element.users.map((id, idx) => (
              <User key={idx} accountId={id} />
            ))}
          </UserGroup>
        ) : (
          <RenderTextOrLink>{element.value}</RenderTextOrLink>
        )
      }
    ]
  }));

  return (
    <>      
      <DynamicTable      
        rows={rows}
        isLoading={isLoading}    
      />
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

I become this warning

warn-once.tsx:12 [@forge/react: String] Warning: The "String" component is deprecated and will be removed on the 28th of August 2025. Please use the "Text" component instead. For more information, visit: https://developer.atlassian.com/platform/forge/ui-kit/components/text/.

||r|@|warn-once.tsx:12|
| --- | --- | --- | --- |
||(anonymous)|@|index.tsx:15|
|||

in the brwoser log. I removed the RenderTextOrLink function , but the warning stays. I searched and founhd no occurence.
I move to antoher instance, but it stays → Just information

Br
Kai

Hi Kai,

thanks for providing the sample code. I was able to reproduce this issue and discovered that in the codebase of Forge UI we’re still using the <String> component. In order to resolve this issue before that component is being removed from the code base, I’ve created a ticket. Feel free to watch https://jira.atlassian.com/browse/ECO-877 to get updates on this.

Your application code is fine, there’s nothing to do on your end. The Forge UI team will make sure that update the DynamicTable component in time.

1 Like